通常说, ajax 请求错误有两种, 一种是网络问题或者代码问题所造成的 400, 500错误等, 另外一种是请求参数后端通不过验证, 由后端抛出的错误
第二种根据不同的后端框架或者程序猿又可以分成两种, 一种是直接返回 json, 用一个 特别的 code 来区别正常请求返回的数据, 如:
{
code: -404,
message: '这是错误信息',
data: '',
}
还有一种就是抛出 http 404 之类的, 然后把错误原因放在 header 里.
在组件写调用 ajax时, 通常都是这么写(这里以 axios 为例):
import axios from 'axios'
axios.get('/user?ID=12345')
.then(function (response) {
if (response.data.code === 200) {
console.log(response.data)
} else {
// 由后端抛出的错误
alert(response.data.message)
}
}).catch(function (error) {
// 由网络或者服务器抛出的错误
alert(error.toString())
})
随着请求越来越多, 这么写也就显得麻烦…所以我们需要封装下, 做一些预处理
下面代码以 axios 为例:
1. 创建 api.js 文件
import axios from 'axios'
import qs from 'qs'
引入我们需要的两个库, 为什么需要用到 qs, 后面会说到
2. 利用拦截器做预处理
请求时的拦截器
axios.interceptors.request.use(config => {
// 这里可以加一些动作, 比如来个进度条开始动作,
NProgress.start()
return config
}, error => {
return Promise.reject(error)
})
请求完成后的拦截器
axios.interceptors.response.use(response => {
return response
}, error => {
// 这里我们把错误信息扶正, 后面就不需要写 catch 了
return Promise.resolve(error.response)
})
这里的return response
返回的是一个对象, 内容如下:
{
// 服务器提供的响应
data: {},
// 服务器响应的HTTP状态代码
status: 200,
// 服务器响应的HTTP状态消息
statusText: 'OK',
// 服务器响应头
headers: {},
// axios 的配置
config: {}
}
做 api 封装
这里一般封装两种方法, 一个是 get 请求, 一个是 post 请求, 有其他情况也可以自行添加
export default {
post(url, data) {
return axios({
method: 'post', // 请求协议
url: url, // 请求的地址
data: qs.stringify(data), // post 请求的数据
timeout: 30000, // 超时时间, 单位毫秒
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
}
})
},
get(url, params) {
return axios({
method: 'get',
url: url,
params, // get 请求时带的参数
timeout: 30000,
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
}
}
这里的 data 为什么需要用qs.stringify(data)
包一下, 主要是配合下面headers
里的Content-Type
, 转成表单提交, 让后端可以直接用 $_POST 拿到数据
这样, 一个大概的封装就完成了
4. 数据统一处理
我们先处理来自网络或者服务器的错误, 定义一个checkStatus
函数
function checkStatus(response) {
// 这里可以加一些动作, 比如来个进度条结束动作
NProgress.done()
// 如果 http 状态码正常, 则直接返回数据
if (response.status === 200 || response.status === 304) {
return response
// 这里, 如果不需要除 data 外的其他数据, 可以直接 return response.data, 这样可以让后面的代码精简一些
}
// 异常状态下, 把错误信息返回去
// 因为前面我们把错误扶正了, 不然像 404, 500 这样的错误是走不到这里的
return {
data: {
code: -404,
message: response.statusText,
data: response.statusText,
}
}
// 如果上面你 return 的是 response.data, 那么这里可以写成
// return {
// code: -404,
// message: response.statusText,
// data: response.statusText,
//}
}
再来处理来自程序端的错误, 创建一个checkCode
的函数
function checkCode(res) {
// 如果状态 code 异常(这里已经包括网络错误, 服务器错误, 后端抛出的错误), 可以弹出一个错误提示, 告诉用户
if (res.data.code !== 200) { // 或者是res.code, 视上面你返回的数据来决定
alert(res.data.message)
}
return res
}
5. 最终代码
import axios from 'axios'
import qs from 'qs'
import NProgress from 'nprogress'
axios.interceptors.request.use(config => {
NProgress.start()
return config
}, error => {
return Promise.reject(error)
})
axios.interceptors.response.use(response => response, error => Promise.resolve(error.response))
function checkStatus(response) {
NProgress.done()
if (response.status === 200 || response.status === 304) {
return response
}
return {
data: {
code: -404,
message: response.statusText,
data: response.statusText,
}
}
}
function checkCode(res) {
if (res.data.code !== 200) {
alert(res.data.message)
}
return res
}
export default {
post(url, data) {
return axios({
method: 'post',
url,
data: qs.stringify(data),
timeout: 30000,
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
}
}).then(checkStatus).then(checkCode)
},
get(url, params) {
return axios({
method: 'get',
url,
params,
timeout: 30000,
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
}).then(checkStatus).then(checkCode)
}
}
6. 在组件中使用
import api from '../api.js' // 改成对应的路径
export default {
async mounted() {
const { data: { code, data }} = await api.post('/api/comment/post', {title: 'title'})
if (code === 200) {
console.log(data)
}
const { data: { code, data }} = await api.get('/api/comment/get', {page: 1})
if (code === 200) {
console.log(data)
}
}
}