文章目录
- 1、请求封装
- 2、问题
- axios 0.21源码
- axios 1.2源码
- 总结
1、请求封装
封装代码:
/**axios封装
* 请求拦截、相应拦截、错误统一处理
*/
import axios from 'axios'
import QS from 'qs';
import { Message } from 'element-ui'
// 环境的切换
if (process.env.NODE_ENV == 'development') {
axios.defaults.baseURL = '/Api'
} else if (process.env.NODE_ENV == 'production') {
axios.defaults.baseURL = '/pfps'
}
// 请求超时时间
axios.defaults.timeout = 15000
// post请求头
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'
// 请求拦截器
axios.interceptors.request.use(
config => {
// 每次发送请求之前判断是否存在token,如果存在,则统一在http请求的header都加上token,不用每次请求都手动添加了
const token = localStorage.getItem('token')
token ? (config.headers.Token = token) : null
config.headers['route'] = localStorage.getItem('route')
return config
},
error => {
return Promise.error(error)
}
)
// 响应拦截器
axios.interceptors.response.use(
response => {
if (response.status === 200) {
//更新token
if (response.headers.token) {
localStorage.setItem('token', response.headers.token)
}
return Promise.resolve(response)
} else {
return Promise.reject(response)
}
},
//服务器状态码不是200的情况
error => {
if (error.response.status) {
switch (error.response.status) {
// 401: 未登录
case 401:
Message({
showClose: true,
message: '未登录',
})
break
// 403 token过期
// 登录过期对用户进行提示
// 清除本地token对象
// 跳转登录页面
case 403:
Message({
showClose: true,
message: '登录过期,请重新登录',
})
// 清除token
localStorage.removeItem('token')
break
// 404请求不存在
case 404:
Message({
showClose: true,
message: '网络请求不存在',
})
break
case 500:
Message({
showClose: true,
message: 'Request failed with status code 500',
})
break
// 其他错误,直接抛出错误提示
default:
console.log(error)
Message({
showClose: true,
message: error.response.data.message,
})
}
return Promise.reject(error.response)
} else {
console.log(error)
Message({
showClose: true,
message: '服务器异常!',
})
}
}
)
/**
* get方法,对应get请求
* @param {String} url [请求的url地址]
* @param {Object} params [请求时携带的参数]
*/
export function get(url, params, type) {
return new Promise((resolve, reject) => {
axios
.get(url, {
params: params,
responseType: type,
})
.then(res => {
resolve(res.data)
})
.catch(err => {
reject(err.data)
})
})
}
/**
* post方法,对应post 序列化请求
* @param {String} url [请求的url地址]
* @param {Object} params [请求时携带的参数]
*/
export function post(url, params) {
return new Promise((resolve, reject) => {
axios.post(url, QS.stringify(params))
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err.data)
})
});
}
/**
* post方法,对应post请求
* @param {String} url [请求的url地址]
* @param {Object} params [请求时携带的参数]
*/
export function postNormal(url, params) {
return new Promise((resolve, reject) => {
axios
.post(url, params)
.then(res => {
resolve(res.data)
})
.catch(err => {
reject(err.data)
})
})
}
/**
* 文件上传
*/
export function postFile(url, params) {
return new Promise((resolve, reject) => {
axios
.post(url, params, {
headers: {
'Content-Type': 'multipart/form-data',
},
})
.then(res => {
resolve(res.data)
})
.catch(err => {
reject(err.data)
})
})
}
/**
* 获取json
*/
export const getJson = function (method) {
return new Promise((resolve, reject) => {
axios({
method: 'get',
url: method,
dataType: 'json',
crossDomain: true,
cache: false,
})
.then(res => {
resolve(res.data)
})
.catch(error => {
reject(error.data)
})
})
}
菜鸟感觉这个封装挺好的,可以注释掉下面提到的那一行,然后自己传参设置!
2、问题
菜鸟在和后端交互时,都是使用的postNormal,但是在axios 0.21版本左右时,发现传递给后端的就是json,但是在aioxs 1.2版本左右时,发现传递给后端的就是form-data。
菜鸟就很不理解,明明我们除了传递文件时会用到new FormData、‘Content-Type’: ‘multipart/form-data’,然后将要传递的值append进去FormData之外,其他全是传递的对象,浏览器是为什么会把对象一下理解成JSON、一下理解成FormData的呢?
百思不得其解的菜鸟和导师一起对比代码,发现真的除了版本,基本上没有区别,所以直接看源码:
axios 0.21源码
直接查看axios 0.21的源码,找到node_modules\axios\lib\defaults.js,查看代码
我们传递的一般都是对象,所以看这个isObject函数,发现里面调用了setContentTypeIfUnset
发现其实setContentTypeIfUnset就是设置请求头,所以可以看出axios默认请求头就是application/json;charset=utf-8
这时候有人就会问,我不是在最上面写了一段这个话吗?
// post请求头
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'
但是其实只要你不是传参传过去的,那么经过axios复杂的判断后,大概率设置是无效的!!!只有传参才是yyds,大神建议也是不要直接设置,最好是你哪里要用就传参改,类似封装的postFile!!!
axios 1.2源码
直接查看axios 1.2源码,找到node_modules\axios\lib\defaults\index.js,查看代码
和上面一样看看这个isObject函数,里面的toURLEncodedForm也是设置请求头,但是不一样的是这个会判断你设置请求头没有,要是设置了,就直接按照你设置的返回
然后application/x-www-form-urlencoded;charset=utf-8 默认就是form-data的数据,所以产生了菜鸟遇见的问题!!!