ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

vue:axios拦截器

2021-06-22 16:02:01  阅读:134  来源: 互联网

标签:axios vue url type 拦截器 params config response


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

一、请求拦截器

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

在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() 方法类似于你浏览器上的刷新页面按钮。

 

标签:axios,vue,url,type,拦截器,params,config,response
来源: https://www.cnblogs.com/zwh0910/p/14917981.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有