ajax 封装(集中 认证、错误、请求loading处理)

一、为什么要对 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

    后续更新。。。

原文地址:https://www.cnblogs.com/wfblog/p/12089942.html