axios 请求拦截封装

221 阅读5分钟
项目中封装
import axios from 'axios'
import Cookies from 'js-cookie'
import router from '@/router'
import qs from 'qs'
import {clearLoginInfo} from '@/utils'
import isPlainObject from 'lodash/isPlainObject'

const http = axios.create({
    baseURL: window.SITE_CONFIG['apiURL'],
    timeout: 1000 * 180,
    withCredentials: true
})

/**
 * 请求拦截
 */
http.interceptors.request.use(config => {
    config.headers['Accept-Language'] = Cookies.get('language') || 'zh-CN'
    config.headers['tenantCode'] = Cookies.get('tenantCode') || ''
    let access_token = Cookies.get('access_token');
    let url = window.location.href.toString();
    let code = url.slice(url.indexOf('/?') + 2, url.indexOf('#/')).split('=')[1];
    if (window.SITE_CONFIG['env'] === 'sit' || window.SITE_CONFIG['env'] === 'uat' || window.SITE_CONFIG['env'] === 'prod') {
        if (!access_token && !code) {
            // 回登录界面
            let clientId = window.SITE_CONFIG['clientId'];
            let uaaUri = window.SITE_CONFIG['apiURL'] + '/auth/oauth/';
            let redirect_uri = window.SITE_CONFIG['redirectUri'];
            let response_type = "code";
            window.location = uaaUri + 'authorize?client_id=' + clientId + '&redirect_uri=' + redirect_uri + '&response_type=' + response_type;
        }
    }
    if (config.url != '/auth/oauth/token') {
        config.headers['Authorization'] = 'Bearer ' + access_token || ''
    }
    if(config.url.indexOf('/zfjd/') != -1){
      config.url = 'http://localhost:8001' +  config.url
    }

    if(config.url.indexOf('/zfba') != -1){
      config.url = 'http://localhost:8001' +  config.url
    }

    // 默认参数
    var defaults = {}
    // 防止缓存,GET请求默认带_t参数
    if (config.method === 'get') {
        config.params = {
            ...config.params,
            ...{'_t': new Date().getTime()}
        }
    }
    if (isPlainObject(config.params)) {
        config.params = {
            ...defaults,
            ...config.params
        }
    }
    if (isPlainObject(config.data)) {
        config.data = {
            ...defaults,
            ...config.data
        }
        if (/^application\/x-www-form-urlencoded/.test(config.headers['content-type'])) {
            config.data = qs.stringify(config.data)
        }
    }
    return config
}, error => {
    return Promise.reject(error)
})
/**
 * 响应拦截
 */
http.interceptors.response.use(response => {
    if (response.data.code === 401 || response.data.code === 10001) {
        clearLoginInfo()
        //router.replace({ name: 'login' })
        return Promise.reject(response.data.msg)
    }
    return response
}, error => {
    console.error(error)
    return Promise.reject(error)
})
/**
 * 封装post请求
 * @param url
 * @param data
 * @returns {Promise}
 */
export function post(url, data = {}) {
    return new Promise((resolve, reject) => {
        http.post(url, data)
            .then(response => {
                resolve(response)
            }, err => {
                reject(err)
            })
    })
}

/**
 * 上传
 * @param url
 * @param data
 */
export function upload(url, file) {
    const formData = new FormData()
    formData.append('file', file)
    return new Promise((resolve, reject) => {
        http.request({
            url: url,
            method: 'post',
            data: formData,
            timeout: 120000
        }).then(response => {
            console.log(response)
            resolve(response.data)
        }).catch(err => {
            reject(err)
        })
    })
}

/**
 * 下载
 * @param url
 * @param data
 */
export function download(url, data) {
    return new Promise((resolve, reject) => {
        http.request({
            url: url,
            method: 'get',
            data: data,
            timeout: 120000,
            responseType: 'blob'
        }).then(res => {
            // 文件下载
            const blob = new Blob([res], {
                type: 'application/vnd.ms-excel'
            })
            // 获得文件名称
            const fileName = '导出的数据.xlsx'
            let link = document.createElement('a')
            link.href = URL.createObjectURL(blob)
            link.setAttribute('download', fileName)
            link.click()
            link = null
            Message.success('导出成功!')
        }).catch(err => {
            reject(err)
        })
    })
}
export default http

/**
 * 封装post请求
 * @param url
 * @param data
 * @returns {Promise}
 */
// export function post(url, data = {}) {
//     return new Promise((resolve, reject) => {
//         http.post(url, data)
//             .then(response => {
//                 resolve(response)
//             }, err => {
//                 reject(err)
//             })
//     })
// }

/**
 * 上传
 * @param url
 * @param data
 */
// export function upload(url, file) {
//     const formData = new FormData()
//     formData.append('file', file)
//     return new Promise((resolve, reject) => {
//         http.request({
//             url: url,
//             method: 'post',
//             data: formData,
//             timeout: 120000
//         }).then(response => {
//             console.log(response)
//             resolve(response.data)
//         }).catch(err => {
//             reject(err)
//         })
//     })
// }

/**
 * 下载
 * @param url
 * @param data
 */
// export function download(url, data) {
//     return new Promise((resolve, reject) => {
//         http.request({
//             url: url,
//             method: 'get',
//             data: data,
//             timeout: 120000,
//             responseType: 'blob'
//         }).then(res => {
//             // 文件下载
//             const blob = new Blob([res], {
//                 type: 'application/vnd.ms-excel'
//             })
//             // 获得文件名称
//             const fileName = '导出的数据.xlsx'
//             let link = document.createElement('a')
//             link.href = URL.createObjectURL(blob)
//             link.setAttribute('download', fileName)
//             link.click()
//             link = null
//             Message.success('导出成功!')
//         }).catch(err => {
//             reject(err)
//         })
//     })
// }

自己封装
  1. 新建require.js配置拦截器/Promise请求封装
import router from '@/router'
// npm 安装axios 命令 cnpm install axios --save
import axios from 'axios'
import { Message } from 'element-ui'

// 创建axios实例
const http = axios.create({
    // 请求头配置 token
    headers: {
        'token': localStorage.getItem('token') || ''
    },
    // 基本路径
    baseURL: '/api',
    // 设置请求连接超时时间
    timeout: 2 * 60 * 1000,
    // 表示跨域请求时是否需要携带凭证,开启后,后端服务器要设置运行开启
    withCredentials: true
})

// request 请求拦截器
http.interceptors.request.use(
    config => {
        // 发起请求时,重新获取最新的token,这一步很重要,因为创建axios实例的时候,获取到的token未必是有效的,或者是没有获取到;
        const token = localStorage.getItem('token')

        // 特殊配置:设置下载获取excel 接口的返回值为blob,这在异步下载文件时会显得很有用。
        if (config.url === '/api/excel/download') config.responseType = 'blob'

        // 特殊配置:登录接口,将请求头的token设置为空字符串
        if (config.rul === '/sys/login') config.headers['token'] = ''
        else config.headers['token'] = token || ''

        // 注意:设置完成后,必须将return 
        return config
    },
    error => Promise.reject(error)
)

// response 响应拦截器 
http.interceptors.response.use(
    response => {
        const res = response.data
        // 特殊配置:code为404,表示资源不存在,跳转到提示页面(404)
        if (res.code === 404) {
            router.push({
                name: 'ErrorPage',
                query: { type: '404' }
            })
            return res
        }
        // 特殊配置:code为401 ,无权限,跳转至提示页面
        if (res.code === 401) {
            router.push({
                name: '401',
                query: { type: 'authority' }
            })
            return res
        }
        // 特殊配置:code为402,token失效,跳转至登录页面
        if (res.code === 402) {
            // 一个特殊功能:访问一个地址没有权限,记录下该地址,登录获取后可以重定向到该地址
            let currentUrl = window.location.href
            const index = currentUrl.indexOf('#')
            const str = currentUrl.substring(index + 1, 6)  // 根据实际情况截取路由地址
            // 如果当前页不是登录页则跳转登录页并缓存当前页地址
            if (str !== '/login') {
                localStorage.setItem('currentUrl', window.location.href)
            }
            router.push({ name: 'login' })
            return res
        }
        // 特殊配置:异步下载文件中有用,一般用不上,导出word,excel文件接口时,注意此时返回的事完整的response,开放 更多信息便于处理下载过程
        const url = response.config.url
        if (url === '/api/word/download' || url === '/api/excel/download') {
            response.config.responseType = 'blob'
            return response
        }

        // 最后,前后段约定code为200表示接口正常响应,去相反值测表示此时接口非正常响应
        // 统一开启接口返回的业务类型的错误提示,这样就不用在每个接口都处理
        // 例如账号密码错误时,自动捕获接口返回的业务类型的错误提示,注意这里的业务类型错误不是BUG。
        if (res.code !== 200) {
            Message({
                message: res.msg || '服务器丢了,请稍后重试!',
                type: 'error',
                duration: 2 * 1000
            })
            return res
        } else return res
    },
    error => {
        // 特殊处理:拦截更改提示信息
        if (error.message.indexOf('timeout') > -1) {
            error.message = '请求超时'
        }
        if (error.message.indexOf('Network') > -1) {
            error.message = '网络错误'
        }
        // 特殊处理:禁止短时间内多次弹出提示,使用节流函数即可
        Message({
             message: error.message,
             type: 'error',
             duration: 2 * 1000
            })
        return Promise.reject(error)
    }
)
// axios结合Promise封装5种常规请求:get / post / put / delete 及用于上传文件的upload


/**
 * POST请求
 * @param {请求地址} url 
 * @param {请求参数} params 
 * @returns {Promise}
 */

export function post (url, params = {}) {
    return new Promise((resolve, reject) => {
        http({
            method: 'post',
            url,
            data: params,
            headers: {
                Accept: 'application/json',
                'Content-Type': 'application/json;charset-URF-8'
            }
        }).then(res => {
            resolve(res)
        }).catch(error => {
            reject(error)
        })
    })
}

/**
 * GET请求
 * @param {请求地址} url 
 * @param {请求参数} params 
 * @returns {Promise}
 */
export function get (url, params = {}) {
    return new Promise((resolve, reject) => {
        http.get(url, params).then(res => {
            resolve(res)
        }).catch(error => {
            reject(error)
        })
    })
}

/**
 * PUT请求
 * @param {请求地址} url 
 * @param {请求参数} params 
 * @returns {Promise}
 */
export function put (url, params = {}) {
    return new Promise((resolve, reject) => {
        http({
            method: 'put',
            url,
            data: params,
            headers: {
                Accept: 'application/json',
                'Content-Type': 'application/json;charset=UTF-8'
            }
        }).then(res => {
            resolve(res)
        }).catch(error => {
            reject(error)
        })
    })
}

export function del (url, params = {}) {
    return new Promise((resolve, reject) => {
        http({
            method: 'delete',
            url,
            data: params,
            headers: {
                Accept: 'application/json',
                'Content-Type': 'application/json;charset=UTF-8'
            }
        }).then(res => {
            resolve(res)
        }).catch(error => {
            reject(error)
        })
    })
}

export function upload (url, file) {
    const formData = new FormData()
    formData.append('file', file)
    return new Promise((resolve, reject) => {
        http({
            method: 'post',
            url,
            data: formData,
            headers: {
                Accept: 'application/json',
                'Content-Type': `multipart/form-data;boundary=${new Date().getTime()}`
            }
        }).then(response => {
            resolve(response)
        }).catch(error => {
            reject(error)
        })
    })
}

  1. Api 方法封装及使用
// 新建 getListApi.js文件
import http, { post, get, put, del, upload } from './http'
let getList = {
    getHomeList: (params) => get('/getList', params),  // 首页获取列表
    getAboutList: (params) => get('/getList', params)   // 其他页获取列表
}
export default getList

// main.js 文件中引入及全局挂载
import api from './utils/api'
Vue.prototype.$api = api

// 页面中使用
async getDatalist() {
    let res = await this.$api.getHomeList()
    this.dataList = res.data.list || []
},