vue中axios请求拦截器和响应拦截器 以及401状态处理

一、axios

在vue中啊 我们不需要去用原生XHR去发 ajax ,因为啊 原生js写起来比较繁琐,并不易我们去开发,   我们可以通过axios 去发ajax?看到axios不要觉得新词就很陌生

官网: axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,本质上也是对原生XHR的封装,只不过它是Promise的实现版本,符合最新的ES规范,有以下特点:

  • 从浏览器中创建 XMLHttpRequests
  • 从 node.js 创建 http 请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求数据和响应数据
  • 取消请求
  • 自动转换 JSON 数据
  • 客户端支持防御 XSRF

复习 axios二次封装 跳转链接

二、请求拦截器

基本格式

// 添加请求拦截器
axios.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
    return config;
  }, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
  });

先知道请求拦截器啊并不是说对请求进行了拦截不让去请求 ,其实目的是在发送请求前进行操作,比如啊 我们在请求头添加token,我们在请求拦截器中添加啊,所有的请求都会经过请求拦截器,是不是不用我们手动挨个去加了,这也是最常用的使用场景了

// 请求拦截器1
instance.interceptors.request.use(function (config) {
  config.header.xxxx1 = 1000
  return config
}, function (error) {
  // 对请求错误做些什么
  return Promise.reject(error)
})

// 请求拦截器2
instance.interceptors.request.use(function (config) {
  config.header.xxxx2 = 'abc'
  return config
}, function (error) {
  // 对请求错误做些什么
  return Promise.reject(error)
})

发送请求中 请求头中除了添加token 也可以添加其他的 上面的代码只是例子,添加后并无作用 

案例 请求头(headers)中携带token例子:

import axios from 'axios'              //引入 axios
import store from '../store/index'     //vuex数据
import router from '../router/auth'    // 路由
export const request1 = axios.create({ //创建一个axios实例
  baseURL: 'http://localhost:8000'
})

// 添加请求拦截器
request1.interceptors.request.use(function (config) {
  // 在发送请求之前做些什么
  // console.log(config)
  const token = store.state.tokenInfo.token  //获取vuex中的token
  if (token) {
    config.headers.Authorization = `Bearer ${token}`  //如果有token 就在请求头上添加token
  }
  return config
}, function (error) {                       
  // 对请求错误做些什么 
  return Promise.reject(error)
})

拦截器写在基地址哦 上面引入一些模块和包 为了更好理解    注意token是在vuex里获取的    也可以通过localStorage中进行获取哦  回顾知识点token持久化

 三、响应拦截器 

所有从后端响应回来的数据都会进入响应拦截器里 ,我们可以在响应拦截器里去进行操作,通常判断token失效

基本写法

// 添加响应拦截器
axios.interceptors.response.use(function (response) {
    // 对响应数据做点什么
    return response;
  }, function (error) {
    // 对响应错误做点什么
    return Promise.reject(error);
  });

案例 401问题

1. 什么时候出现401 ?  token过期在进行用户操作,token一般都会有时间限制,比如十二小时后token过期 过期后的token再去权限操作就会报出401错误

 

 2.模拟token失效 对于token失效我们不能干等12小时 这也太漫长了,但是我们可以模拟token失效  通过修改vuex 里的token  因为vuex中的token是响应式的 我们只需要对齐进行修改,注意不要刷新!!(刷新后token又重新获取了) 

模拟token失效 在vuex中 删除token中的几个字符就可以模拟token失效 , 因为我下次操作肯定 还会发请求 下次带着错误的token和失效一个道理

3.  refresh_token 我们在图中看到了refresh_token(这也是后端提供给我们的,保存在了vuex里,接下来讲他是起到什么作用)

(1) 如果token失效后 例如失效期是一小时  用户发现突然操作没有权限了  只能去重新登录 重新获取token  这是对用户非常不好的体验,每次一小时都要重新登录一次,用户骂骂咧咧的删除了网页

(2) 所以啊 这时候refresh_token的作用来了,它的作用呢也可以作为用户的令牌,token失效后,我们可以通过refresh_token去重新获取token 当然这些操作都是报了401错误在响应拦截器里操作的,对于refresh_token可以通过响应拦截器做到 用户无感的体验 让用户感觉不到任何 操作,但是背后的程序员付出了很多, 哎 果然用户体验的背后都有一个伟大的程序员, 当然他也是有时间限制的 一般为7天/14天当然也是后端设置的

(3)这里啊有个疑问 为什么不能直接设置14天 或者永久呢 搞这么麻烦? 个人理解的是 如果token呢一直一样 那也就失去了保留token 的意义所在,那我还要token干嘛,所以呢第一点 保证token不被盗取,能够保证用户的安全性更高,第二点也差不多,因为refresh_token是去请求后端的,这也是请求后能告诉后台用户在连接,能够得到响应。(希望大家看到能补充一最好)

4. 接下来先看一张具体的流程图(有 · 复杂哦,仔细看)

具体步骤

对于某次请求A,如果是401错误 (2)

- 有refresh_token,用refresh_token去请求回新的token (3)
- 新token请求成功 (4)
- 更新本地token (5)
- 再发一次请求A   (6)
- 新token请求失败
- 携带请求地址,跳转到登陆页
- 没有refresh_token,说明没有登陆
- 携带请求地址,跳转到登陆页

转换为代码 为了更好理解 把每一句的注释写在后面 (仔细看很好理解,别觉得多一扫而过)

import store from '../store/index'
import router from '../router/auth'
request1.interceptors.response.use(function (response) {
  // 对响应数据做点什么
  return response
}, async function (error) {
  // 对响应错误做点什么
  console.dir(error)
  const refreshToken = store.state.tokenInfo.refresh_token // 拿到refres_token 定义变量不能和引入的变量名重复 例如 const store
  if (error.response.status === 401) { // 在error对象中 可以看到状态 是否为401
    if (refreshToken) {
      // 1.  token 过期的情况 判断如果有refreshToken 去发ajax
      try {
        const res = await axios({
          url: 'http://localhost:8000/v1_0/authorizations',
          method: 'PUT',
          headers: { // headers 不能按接口文档抄 H不能大写!!!!
            Authorization: `Bearer ${refreshToken}`
          }
        })
        const newToken = res.data.data.token // 拿到新的token再去发请求
        console.log(newToken)
        // 发请求调用vuex的mutations
        store.commit('setTokenInfo', { token: newToken, refresh_token: refreshToken }) // 这里的token 和 refresh_token要和之前定义变量匹配(vuex中)
        return request1(error.config) // 哪里发请求就在哪调用 这里指的是只是修改了新的token  并没有修改error其他的值 只是重新发请求
      } catch (error) {
        // 2.  refreshToken 也过期了 但是登录着呢 但是之前的已经登录已经跳不过去了 所以要设置为空 (这里之前设置过登录用户无法访问登录页 )
        store.commit('setTokenInfo', {}) // 传一个空的token就可以了
        // encodeURIComponent 因为我们在路由传参的时候遇见&符后面的参数不能转码 所以我们要把整句转换成编码形式
        // 下面代码解释 例如我从文章页进行操作 没有token自动跳到登录页 登录之后用户想的是继续访问文章页 并不是想访问主页 所以我们就要保存刚才的路径
        // 通过'login?参数='+刚才的路径地址  这样登录页面就能拿到参数  登陆成功后进行跳转    this.$router.push(this.$route.query.returnUrl || '/')
        router.push('/login?returnUrl=' + encodeURIComponent(router.currentRoute.fullPath)) // router.currentRoute 相当于 vue中的$route
        return Promise.reject(new Error('refresh_token清空')) // 抛出错误不然会可能提示执行成功
      }
    } else { // 3.  如果没有refresh_token  去登录 和上面同样的操作
      console.log('未获取到refreshToken,所以要去登录')
      store.commit('setTokenInfo', {})
      router.push('/login?returnUrl=' + encodeURIComponent(router.currentRoute.fullPath)) // router.currentRoute 相当于 vue中的$route
      return Promise.reject(new Error('refresh_token不存在'))
    }
  }
})

挪出一部分作为笔记哈 也是常见不会写或者错误

1.    router.currentRoute 相当于 vue中的$route

2.   headers: { // headers 不能按接口文档抄 H不能大写!!!!
            Authorization: `Bearer ${refreshToken}`
          }

3.   store.commit('setTokenInfo', { token: newToken, refresh_token: refreshToken }) // 这里的token 和 refresh_token要和之前定义变量匹配(vuex中)

4.     encodeURIComponent 因为我们在路由传参的时候遇见&符后面的参数不能转码 所以我们要把整句转换成编码形式

        // 下面代码解释 例如我从文章页进行操作 没有token自动跳到登录页 登录之后用户想的是继续访问文章页 并不是想访问主页 所以我们就要保存刚才的路径

        // 通过'login?参数='+刚才的路径地址  这样登录页面就能拿到参数  登陆成功后进行跳转    this.$router.push(this.$route.query.returnUrl || '/')

        router.push('/login?returnUrl=' + encodeURIComponent(router.currentRoute.fullPath)) // router.currentRoute 相当于 vue中的$route

5.  return request1(error.config) // 哪里发请求就在哪调用 这里指的是只是修改了新的token

有了上面的操作 啊 token失效后 又去拿refresh_token又去请求了一遍 ,最后请求过来的数据拿到最新的token ,再去保存到vuex中,然后再去进行操作  return request1(error.config) 这句话不要以为error就是表示错误信息,它里面其他的信息没变,我们只是重新获取了token ,重新发了一遍请求,当然是哪里调用就在哪里重新请求,最主要的一句就是 让用户无感!!!!!

Vue 项目,可以通过以下步骤封装 axios请求拦截响应拦截: 1. 安装 axios ``` npm install axios --save ``` 2. 创建一个 axios 实例 在项目,一般会有多个接口请求,为了方便管理和配置,可以创建一个 axios 实例来处理所有的请求。在 `src` 目录下新建一个 `api` 文件夹,然后在该文件夹下新建一个 `http.js` 文件,输入以下代码: ```JavaScript import axios from 'axios' const http = axios.create({ baseURL: process.env.VUE_APP_BASE_URL, timeout: 5000, headers: { 'Content-Type': 'application/json;charset=UTF-8' } }) export default http ``` 上述代码,我们创建了一个名为 `http` 的 axios 实例,并设置了一些默认配置,如请求的基础 URL、请求超时时间、请求头等。 3. 设置请求拦截器 请求拦截器可以在请求发送前做一些处理,如添加请求头、添加 loading 等。在 `http.js` 文件添加以下代码: ```JavaScript http.interceptors.request.use(config => { // 添加 loading // ... // 添加请求头 // ... return config }, error => { return Promise.reject(error) }) ``` 4. 设置响应拦截器 响应拦截器可以在接收到响应后做一些处理,如判断响应状态码、关闭 loading 等。在 `http.js` 文件添加以下代码: ```JavaScript http.interceptors.response.use(response => { // 判断响应状态码 if (response.status === 200) { return Promise.resolve(response.data) } else { return Promise.reject(new Error(response.statusText)) } // 关闭 loading // ... }, error => { return Promise.reject(error) }) ``` 5. 通过 `http` 实例发送请求 在需要发送请求的组件,可以通过 `http` 实例发送请求。例如,获取用户列表的代码如下所示: ```JavaScript import http from '@/api/http' export default { data() { return { userList: [] } }, mounted() { http.get('/user/list').then(res => { this.userList = res.data }) } } ``` 上述代码,我们通过 `http` 实例发送了一个 GET 请求请求的 URL 为 `/user/list`。请求成功后,将响应数据赋值给 `userList`。 通过以上步骤,我们就成功地封装了 axios请求拦截响应拦截。在实际开发,我们还可以根据项目需求进行更加复杂的封装。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值