一、为什么要对 ajax 进行封装: (在使用antd pro 开发项目时,里面默认是把请求进行了封装的,放在 utils/request.js 中。使用起来非常方便 https://pro.ant.design/docs/server-cn )
1、便于统一处理 POST,GET 等请求参数,请求头,以及错误提示信息等。甚至 loading处理 。
2、一个项目中 请求头、错误处理、loading 处理一把都是一样的。封装之后,层次结构清晰;代码减少,且页面中的逻辑只要关心对应的逻辑就可以了。
3、如果 请求上有token 判断是否登入,接口还要引导登入。
请求中不同域判断判断是否登入,需要前端手动在header上加上tooken。
4、如果 后端请求超时、以及 后端服务器 宕机,要做好应对机制。跳转到指定页面 或者 弹出提示框。这些都是可以在封装的ajax上处理的。
5、网络请求状态码为200,但接口态码非200(或 0000)的Response 包装成异常信息。这样页面中的业务逻辑就不需要判断 接口状态码非成功的情况了。
6、浏览器和服务器,ip地址通的话,服务器才会有返回码。如果浏览器是断网的话,服务器是没有返回错误码的。下面代码是基于axios封装的错误处理。
/** * 异常处理程序 */ const errorHandler = error => { if (error.response) { // 请求已发出,但服务器响应的状态码不在 2xx 范围内 console.log(error.response) const errorText = codeMessage[error.response.status] || error.response.statusText const { status, config } = error.response console.log(`请求错误 ${status}:${config.url}${errorText}`) } else { // 请求没有响应。即网络发生异常,无法连接服务器,比如 浏览器或服务器 断网。 console.log('网络异常', error.message) } console.log(error.config) }
二、axios 的二次封装:https://www.mmxiaowu.com/article/589af8cde9be1c5b21ef8e9c 或 https://blog.csdn.net/weixin_33769125/article/details/93993438(推荐这个)
axios 官网文档:https://www.kancloud.cn/yunye/axios/234845
说明:axios 拦截器,return false(或者抛出异常)。就不会发送请求出去。
1、错误反馈:
const codeMessage = { 200: '服务器成功返回请求的数据。', 201: '新建或修改数据成功。', 202: '一个请求已经进入后台排队(异步任务)。', 204: '删除数据成功。', 400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。', 401: '用户没有权限(令牌、用户名、密码错误)。', 403: '用户得到授权,但是访问是被禁止的。', 404: '发出的请求针对的是不存在的记录,服务器没有进行操作。', 406: '请求的格式不可得。', 410: '请求的资源被永久删除,且不会再得到的。', 422: '当创建一个对象时,发生一个验证错误。', 500: '服务器发生错误,请检查服务器。', 502: '网关错误。', 503: '服务不可用,服务器暂时过载或维护。', 504: '网关超时。', };
三、我对 axios 的二次封装:
封装方式1:
import axios from 'axios' // import Qs from 'qs' const codeMessage = { 200: '服务器成功返回请求的数据。', 201: '新建或修改数据成功。', 202: '一个请求已经进入后台排队(异步任务)。', 204: '删除数据成功。', 400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。', 401: '用户没有权限(令牌、用户名、密码错误)。', 403: '用户得到授权,但是访问是被禁止的。', 404: '发出的请求针对的是不存在的记录,服务器没有进行操作。', 406: '请求的格式不可得。', 410: '请求的资源被永久删除,且不会再得到的。', 422: '当创建一个对象时,发生一个验证错误。', 500: '服务器发生错误,请检查服务器。', 502: '网关错误。', 503: '服务不可用,服务器暂时过载或维护。', 504: '网关超时。' } /** * 异常处理程序 */ const errorHandler = error => { alert('请求失败') if (error.response) { // 请求已发出,但服务器响应的状态码不在 2xx 范围内 console.log(error.response) const errorText = codeMessage[error.response.status] || error.response.statusText const { status, config } = error.response console.log(`请求错误 ${status}:${config.url}${errorText}`) } else { // 请求没有响应。即网络发生异常,无法连接服务器,比如 浏览器或服务器 断网。 console.log('网络异常:与服务器断开链接') } console.log(error.config) } // 设置请求超时时间 axios.defaults.timeout = 10000 // 设置post请求头 axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8' // 请求拦截 axios.interceptors.request.use(config => { // 在发送请求之前做些什么 验证token之类的 alert('发送请求前') return config }, error => { alert('抛出错误') // 对请求错误做些什么 return Promise.error(error) }) // 响应拦截 axios.interceptors.response.use(response => { // 对响应数据做点什么 alert('响应请求后') return response }, error => { alert('响应错误') // 对响应错误做点什么 return Promise.reject(error) }) // 封装get方法和post方法 /** * get方法,对应get请求 * @param {String} url [请求的url地址] * @param {Object} params [请求时携带的参数] */ export function get (url, params) { return new Promise((resolve, reject) => { axios.get(url, { params: params }).then(res => { resolve(res.data) }).catch(err => { errorHandler(err) reject(err) }) }) } /** * post方法,对应post请求 * @param {String} url [请求的url地址] * @param {Object} params [请求时携带的参数] */ export function post (url, params) { return new Promise((resolve, reject) => { axios.post(url, params) .then(res => { resolve(res.data) }) .catch(err => { errorHandler(err) reject(err) }) }) }
封装方式2:
强调下:页面中 所有 请求回来的数据,一定要做好 undefined (没有这个字段时,js中这个字段值就是undefined)、null 引起的报错机制。这不是接口程序错误,这是正常情况的数据。比如当天报名人员信息,没有人报名,数据库中当然是没有数据的。
最里面那层的属性是 undefined和null 是不会报错的,但是上一层属性一定要判断是不是undefined或null。使用逻辑运算符就可以。
data || {} // data 对象没有数据,需要给个默认的{ } 或 []
说明下: 后端返回的字段对应的数据,数据类型是不会变的(可能会是null),如果 返回的数据类型错了(比如应该是一个对象,结果返回一个字符串回来),那就是后端的问题了,需要他们处理。
最新的 es 好像 将要有一个新的API 解决这个问题 :Optional Chaining https://www.jianshu.com/p/e9ed7660034e
ajax 响应数据处理
场景说明:前后端分离的开发环境下,前后端并行开始时势必会产生双方定义字段完全不统一的问题,实际开发中后台会根据需求更换字段。https://blog.csdn.net/qq_15390381/article/details/103803523
如果返回的数据只是在ajax回调函数中使用下,后台改了,前端同步去改,问题不是很大;如果返回的字段在其他很多地方都有使用的话,那改起来就比较麻烦。需要在所有引用这个字段的地方,都去修改。如:
<!-- 这里的name直接是根据接口返回数据的字段定的,一但后台接口字段改了,其它的使用这个字段的地方都要改 --> <h3>{{userMsg.name}}</h3>
ajax(url, res => { this.userMsg = res.data }) /* res.data返回的对象是: { name: '', age: '', idCode: '', phone: '', ... } */
优化思路:页面中使用后台接口的字段,都是 js 自己命名的,不随后台接口字段而改变。但是后台的数据响应回来后,做一个字段的映射。把自己命名的字段和接口返回的字段对应起来【两种的命名可以相同也可以不同,互不影响】。
优点是,① 可以给相应字段 设置默认值;② 后端接口变动,只要改一下映射关系就可以了;③ 后端接口数据很多时,可以只映射需要的字段数据。
缺点是,如果映射的对象 层级比较多,映射就不好处理了。(所以要不要进行字段映射,完全看后台字段是不是会经常改动。一般接口字段都是稳定,要改也是个别几个,所以基本不用去映射)
实现方案: 参考,https://blog.csdn.net/qq_15390381/article/details/103803523 或 http://www.mamicode.com/info-detail-2932906.html
后续更新。。。