前端401错误 & 解决方法:响应拦截器

Posted 接着奏乐接着舞。

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端401错误 & 解决方法:响应拦截器相关的知识,希望对你有一定的参考价值。

目录

1.该问题出现的原因

2.处理401问题的解决方案原理

3.使用响应拦截器解决问题


1.该问题出现的原因

在前后端分离项目中,最常见的是前端点击登录后,后端返回token字符串,这个token可以看作是一个“令牌”,就比如你去酒店办理入住后,拿到的房卡,那代表你有着进去房间的权限。


1. 登录用户的token过期 

token是具有时效性的,生活中,如你登录腾讯视频,接下来几天你再登录就不用输入账号密码,而时间很长如半个月后,你还要重新输入账号密码登录,这个过程就是token过期。

具体多久过期,一般是和后端商量着来,后台管理类项目如企业内部的项目为了安全性且并不会过多的考虑用户体验,一般设为很短或者干脆不做这个。

而像腾讯视频,淘宝,京东之类的商业类项目需要考虑用户体验,且对于安全性要求并不高,一般设置为7~14天比较合适。


2. 用户未登录情况,返回401错误,应该回到登录页(这个不一定是401错误)


3.小结:很普遍的功能,80%的项目都会做这个功能


2. 处理401问题的解决方案原理


完整的逻辑为: 

 前端请求接口api --> 返回401错误 --> 前端判断是否有refresh_token -->如果有就用refresh_token请求新的token --> 后台成功返回一个新的token给我们 --> 更新vuex+本地存储持久化 --> 然后重新发送请求 --> 带上新的token请求数据

当然,如果没有refresh_token就老老实实去登录吧!



 

方案: 目前常见的处理方式是:当用户登陆成功之后,返回的token中有两个值


原理:一个是token,他的有效期是2小时(举例),一个是姑且称为refresh_token,他的有效期长,比如是14天,假设用户登录后2小时后,token过期了,那么我们看一下refresh_token在不在,在的话,就用refresh_token再次发送,后端会返回一个新的token。


核心点:1.解决401问题重点在于让用户“无感”,也就是说用户不知道token过期也不需要用户再次登录,需要的是我们程序员去处理。

               2.解决这个问题的地方在响应拦截器


3.使用响应拦截器解决问题


3.1 作用

所有从后端回来的响应都会集中进入响应拦截器中,如果发生401错误就可以解决

 

 


 

以下是我封装的响应拦截器(可以通用),主要完成两件事:

处理401问题,以及注入token

import router from '../router/auth.js'
 
 
// 响应拦截器
request.interceptors.response.use(function (response) 
  console.log('响应拦截器', response)
  return response
, async function (error) 
  // 如果发生了错误,判断是否是401
  console.dir(error)
  if (error.response.status === 401) 
    // 出现401就在这里面 开始处理 ---
    console.log('响应拦截器-错误-401')
    const refreshToken = store.state.tokenInfo.refresh_token
    // if (有refresh_token)        ---- 有refresh_token
    if (refreshToken) 
      // 1. 请求新token
      try 
        const res = await axios(
          url: 'http://localhost:8000/v1_0/authorizations',
          method: 'PUT',
          headers: 
            Authorization: `Bearer $refreshToken`
          
        )
        console.log('请求新token', res.data.data.token)
        // 2. 保存到vuex
        store.commit('mSetToken',    // mSetToken是前面定义的mutations名字
          refresh_token: refreshToken,
          token: res.data.data.token
        )
        // 3. 重发请求
        //    request是上面创建的axios的实例,它会自动从vuex取出token带上
        return request(error.config)
       catch (error) 
        // 1. 清除token
        store.commit('mSetToken', )  
        // 2. 去到登录页(如果有token值,就不能到login)
        const backtoUrl = encodeURIComponent(router.currentRoute.fullPath)
        router.push('/login?backto=' + backtoUrl)  
        return Promise.reject(error) 
      
     else 
       // 如果没有refresh_token的时候   ----没有refresh_token
      // 1.去到登录页
      // 2.清除token
      store.commit('mSetToken', )
      const backtoUrl = encodeURIComponent(router.currentRoute.fullPath)  // 回到原来跳过来的的页面,不加?后面的一串就会到首页
      router.push('/login?backto=' + backtoUrl)
      return Promise.reject(error)  // 返回错误信息
    
   else 
    return Promise.reject(error)
  
)

前端Uncaught (in promise) 的解决方法及原因

问题:在Vue项目中使用axios调用一个第三方的接口时,前端无法获取到接口返回值,检查控制台Network发现接口请求已经正常发出并且有数据返回,但是控制台Console报了这么一个错误

 

 上图可以看到接口请求正常响应并有返回,控制台却一直报错 Uncaught (in promise) 

排查一番之后发现,是接口响应拦截器里面的问题,原本封装好的请求方法里面response.data.code == 0才算请求成功,因为我们自己这边的接口请求成功时响应的code值为0,但是今天访问的是第三方的接口,这个接口请求成功时返回的code值为200,从上图可看出,所以这个请求的响应被拦截掉了,从而Promise.reject(rejection)报错。

解决办法:修改拦截器里面的判断,将code为200也视为成功(这里根据实际接口返回做修改)

axios.interceptors.reponse.use(res => {
  // 请求成功对响应数据做处理,此处返回的数据是axios.then(res)中接收的数据
  if (res.code ==0 || res.code == 200) {
     // code值为 0 或 200 时视为成功
     return Promise.resolve(res)
  }
  return Promise.reject(res)
}, err => {
    // 在请求错误时要做的事儿
    ...
    // 此处返回的数据是axios.catch(err)中接收的数据
    return Promise.reject(err)
})

修改完之后,前端就能正常拿到接口的返回值了。

以上方法可供参考,可能还有其他造成这个报错的原因

以上是关于前端401错误 & 解决方法:响应拦截器的主要内容,如果未能解决你的问题,请参考以下文章

AngularJS成功401拦截还是抛出401

前端Uncaught (in promise) 的解决方法及原因

如果有 401 响应,角度拦截器会注销应用程序吗?

aws cognito && apiGateway 返回状态 401

Angular 4 和 OAuth - 拦截 401 响应,刷新访问令牌并重试请求

Token过期处理