vue:axios拦截器

Posted zwh2020

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue:axios拦截器相关的知识,希望对你有一定的参考价值。

拦截器分两类:请求拦截器和响应拦截器

一、请求拦截器

在请求发出之前设置一些信息。比如说设置请求头,

use方法参数即第一个函数的形参中通过config来做信息的配置,配置完之后,必须把config返回,这样才能完成拦截器的功能。第二个函数用于处理错误的信息。

用拦截器的方式配置请求头会更加灵活。拦截器中可以通过config获取更多的信息,比如url地址,这样就可以根据url作出判断,某些url可以添加一个请求头,而别的url不添加请求头。

 

通过拦截器,我们可以控制所有的请求。

下面来分析项目中的请求拦截器

// request拦截器
service.interceptors.request.use(

  config => {
    if (store.getters.token) {
      config.headers[\'Authorization\'] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
    }

    // params参数编码
    let url = config.url;
    console.log(url)

    if (config.params) {
      console.log(config.params)
      url += \'?\';
      let keys = Object.keys(config.params);
      console.log(keys)
      for (let key of keys) {
        if (config.params[key] !== null && config.params[key] !== "") {
          url += `${key}=${encodeURIComponent(config.params[key])}&`;
        }
      }
      console.log(url)
      url = url.substring(0, url.length - 1);
      console.log(url)
      config.params = {};
    }
    config.url = url;
    return config;
  },
  error => {
    console.log(error) // for debug
    Promise.reject(error)
  }
)

下面来分析代码:


medMaterial.getAuditorsByPrepareId({
prepareId: edit.id,
productId: edit.productId,
enterpriseId: edit.enterpriseId1
}).then(res => {
if (res.success) {
.........

js中的代码为:

getAuditorsByPrepareId(query){
    return request({
      url: \'/medMaterial/getAuditorsByPrepareId\',
      method: \'post\',
      params: query
    })
  },

当我们发出上面的一个请求,请求拦截器就会将参数的值进行编码,然后将参数通过?号拼接到url中。拼接后的url如下所示:

http://localhost:8008/api/medMaterial/getAuditorsByPrepareId?prepareId=444&productId=20663&enterpriseId=81

1、先判断token是否存在,如果存在,让每个url都添加请求头Authorization

2、通过config获取url:/medMaterial/getAuditorsByPrepareId

3、通过url获取params:{prepareId: 444, productId: 20663, enterpriseId: 81}

4、先给url拼接一个?号:/medMaterial/getAuditorsByPrepareId?

5、获取config中参数params中所有的key即keys:["prepareId", "productId", "enterpriseId"]

6、遍历keys,如果params中key的值不为null或不为空字符串,先对key的值进行encodeURIComponent编码,编码后的结果放入${}中,key不编码。由于该方法encodeURIComponent不会对 ASCII 字母和数字进行编码,故对value进行编码后的结果url仍然为:/medMaterial/getAuditorsByPrepareId?prepareId=444&productId=20663&enterpriseId=81&

7、去掉最后的&得到的url:/medMaterial/getAuditorsByPrepareId?prepareId=444&productId=20663&enterpriseId=81

再比如备货详情中,点击查看按钮,发送的请求如下:

const query = { type: row.type,materialName: row.materialName,materialCode: row.materialCode,batch: row.originalBase }
        console.log(query)
        prepare.queryFullChain(query).then(response => {
          console.log(response)
          if(response.success){

js中的代码如下:

queryFullChain(query) {
    return request({
      url: \'/prepare/queryFullChain\',
      method: \'post\',
      params: query
    });
  },

1、先判断token是否存在,如果存在,让每个url都添加请求头Authorization

2、通过config获取url:/prepare/queryFullChain

3、通过url获取params:{type: "0", materialName: "天麻", materialCode: "TM001", batch: "11"}

4、先给url拼接一个?号:/prepare/queryFullChain?

5、获取config中参数params中所有的key即keys:["type", "materialName", "materialCode", "batch"]

6、遍历keys,如果params中key的值不为null或不为空字符串,先对key的值进行encodeURIComponent编码,编码后的结果放入${}中,key不编码。由于该方法encodeURIComponent不会对 ASCII 字母和数字进行编码,故对value进行编码后的结果url为:/prepare/queryFullChain?type=0&materialName=%E5%A4%A9%E9%BA%BB&materialCode=TM001&batch=11&,注意对中文进行了编码。

7、去掉最后的&得到的url:/prepare/queryFullChain?type=0&materialName=%E5%A4%A9%E9%BA%BB&materialCode=TM001&batch=11

二、响应拦截器

浏览器在获取响应数据之前对数据做一些加工处理。

Use方法的第一个参数即第一个函数的形参res表示后台返回的具体数据信息。res并不是实际的数据,而是axios包装的对象,通过对象中的data才能拿到数据。这和之前获取后台数据的时候是一样的。

如果在调用接口的时候,只关心实际的数据而不需要包装对象,故可以集中的在响应拦截器做一些加工。如下所示

这样再次发请求调接口的时候,最终拿到的就是实际的数据了。

这样的话,以后我们调用任何接口,所有then当中得到的数据,都是我们实际需要的后台返回来的数据。不需要再通过点data的方式获取数据了

 项目中的响应拦截器如下:

// response 拦截器
service.interceptors.response.use(
  response => {
    /**
     * code为非20000是抛错 可结合自己业务进行修改
     */
    const headers = response.headers
    // 此类为下载流文件,不拦截
    if (headers[\'content-type\'] === \'application/octet-stream;charset=utf-8\') {
      return response
    }
    if (headers[\'content-type\'] === \'arrayBuffer;charset=UTF-8\') {
      return response
    }
    const res = response.data
    if (res.code !== 1) {
      if(res.code === 301){
        Message({
          message: res.msg,
          type: \'error\',
          duration: 5 * 1000
        })
        location.reload()
      }

      // 50008:非法的token; 50012:其他客户端登录了;  50014:Token 过期了;
      if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
        MessageBox.confirm(
          \'你已被登出,可以取消继续留在该页面,或者重新登录\',
          \'确定登出\',
          {
            confirmButtonText: \'重新登录\',
            cancelButtonText: \'取消\',
            type: \'warning\'
          }
        ).then(() => {
          store.dispatch(\'FedLogOut\').then(() => {
            location.reload() // 为了重新实例化vue-router对象 避免bug
          })
        })
      }
      return Promise.reject(\'请重新登录\')
    } else {
      return response.data
    }
  },
  error => {
    console.log(\'err\' + error) // for debug
    Message({
      message: \'请求超时,请联系管理员!\',
      type: \'error\',
      duration: 5 * 1000
    })
    return Promise.reject(error)
  }
)

 响应拦截器代码分析:

1、由于后台EasyPOIUtils在下载Excel时,设置了响应头,如下:

response.setHeader("Content-type", "text/html;charset=UTF-8");
            response.setCharacterEncoding("utf-8");//设置编码集,文件名不会发生中文乱码

            response.setContentType("application/force-download");//
            response.setHeader("content-type", "application/octet-stream");
            response.addHeader("Content-Disposition", "attachment;fileName=" + new String(fileName.getBytes(), "utf-8"));// 设置文件名
            response.addHeader("Content-Length", "" + file.length());
            response.setHeader("Access-Control-Allow-Origin", "*");

 故响应拦截器不拦截。

2、由于在下载图片时,PtsFileController中设置了响应头,

@RequestMapping(value = "/picDownload")
    public void picDownload(  String filePath,HttpServletResponse response)throws Exception{
        File file = new File(filePath);
        ServletOutputStream  out = null ;
        BufferedInputStream buf  = null ;
        response.setHeader("Content-Type","arrayBuffer");
        try{
            buf = new BufferedInputStream(new FileInputStream(file));
            out = response.getOutputStream();
            byte[] buffer =  new byte[1024];
            while(buf.read(buffer) != -1){
                out.write(buffer);

            }
            out.flush();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(buf!= null){
                buf.close();
            }
            if(out != null){
                out.close();
            }
        }
    }

 故响应拦截器不拦截。

3、response并不是实际的数据,而是axios包装的对象,通过对象中的data才能拿到数据.

4、由于后台ResultCode类中设置请求成功的code为1,

/**
     * 请求成功Result
     */
    public static final int SUCCESS=1;

当我们要返回数据给前端时,会设置code为success

result.setSuccess(false);
                result.setMsg("请修改密码后再登录!");
                result.setCode(ResultCode.SUCCESS);
                return result;

此时res.code等于1,返回response.data给前端。

如果res.code不等于1,由于后台设置了用户登录超时的code为301

/**
     * 用户未登录或登录超时
     */
    public static final int NO_LOGIN = 301;

当我们要返回数据给前端时,会设置ResultCode为NO_LOGIN

User u = (User) redisService.get(pre + "TPS-TOKEN" + token);
            if (null == u) {
                rs.setSuccess(false);
                rs.setCode(ResultCode.NO_LOGIN);
                rs.setMsg("非法登录或者token已失效!");
                return rs;
            }

此时res.code为301,则进行错误消息的提示,type为error,message为后台返回的消息,duration为持续的时长,这里为5s.

location.reload()方法用于刷新当前文档。reload() 方法类似于你浏览器上的刷新页面按钮。

 

以上是关于vue:axios拦截器的主要内容,如果未能解决你的问题,请参考以下文章

vue+axios完美实现前端路由拦截

vue axios请求/响应拦截器

vue axios 拦截器

Vue-axios拦截器401错误

Vue----axios拦截器的使用

vue全家桶进阶之路47:Vue3 Axios拦截器封装成request文件