添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
安静的油条  ·  WMI-Win32_DiskDrive ...·  1 年前    · 

业务场景:有几个外部系统的接口,需要先通过一个获取 token 的接口获取到 token 后续业务接口需要在请求头中的 Authorization 带上 token。刚开始我在登录后获取了一次 token 并存储在 store 中,业务接口使用过的时候直接获取就可以了。后来发现这个 token 经常莫名其妙的过期,刚开始想着通过同步获取 token 后再请求业务接口,但是这些业务接口分散在多个子页面中,就会造成多写很多业务代码。所决定在这些外部接口使用一个特定的 axios 实例并在  response 的拦截处统一处理 token 问题

axios 实例代码:

import axios from 'axios'
import store from '@/store'
import { getTokenInfo } from '@/api/prophetApiMarket'
import { Message } from 'element-ui'
import debounce from 'lodash/debounce'
// 多个错误信息合并
const showMessage = debounce(function (message) {
  Message({
    message: message,
    type: 'error',
    duration: 3 * 1000
}, 300)
// 最大重复次数
const MAXREPEAT = 3
// 记录当前接口重复请求次数,超过3次就不再请求了
let countState = {}
// 重新设置token
async function refreshToken(ajax, response) {
  // 获取token,data就是token字符串
  const { data } = await getTokenInfo()
  store.commit("setProphetToken", data)
  // 重新请求当前之前没有token 的接口
  response.config.headers['Authorization'] = "Bearer " + data
  ajax.defaults.headers.common['Authorization'] = "Bearer " + data
// 初始实例
const ajax = axios.create({
  timeout: 10000,
  baseURL: '/prop'
// 返回拦截
ajax.interceptors.response.use(async response => {
  if (response.status === 200) {
    const { data } = response
    // token过期
    if (data.code === 403 || (data.code === 406 && data.message === 'TOKEN已过期')) {
      countState[response.config.url] = countState[response.config.url] ?? 0
      // 最大重复次数
      if (countState[response.config.url] < MAXREPEAT) {
        // 计数
        countState[response.config.url]++
        // 获取token
        await refreshToken(ajax, response)
        // 重新请求
        return ajax(response.config)
      } else {
        // 重置计数,并返回结果
        countState[response.config.url] = 0
        return data
    return data
  } else {
    console.log('responseError: ' + response.data.message)
    showMessage(response.data.message)
    return Promise.resolve(response)
}, error => {
  console.log('responseError: ' + error)
  showMessage(error.message)
export default ajax

引入上面文件使用:

import ajax from './request.js'
import store from '@/store'
// getToken
export const getTokenInfo = () => {
  return ajax.post('/aaaa', {
    secretKey: store.state.envVar.key,
    userId: store.state.envVar.id
// getDataA
export const getDataA= (params) => {
  return ajax.post('/getDataA', params)

上面的 getDataA 是需要设置 Authorization 请求头的,当调用之后,response 拦截且匹配到 token 已过期就会先去获取 token 然后再重新请求

axios使用详见官网:axios中文文档|axios中文网

axios+ token +refreshToken 前端登录后,后端返回token和refresh_token,当token值过期的时候就用refresh_token去获得新的token 为了防止多次刷新token值,如果refreshToken接口还没有返回,此时如果再有一个请求进来,会再次执行refreshToken ,这样就会导致多次执行刷新token接口,因此需要防止这个问题,我们可以在request.js中使用一个参数例如flag来标记当前是否为正在刷新的状态,如果正在刷新则不在
vue-resource 拦截器使用 在vue项目使用vue-resource的过程中,临时增加了一个需求,需要在任何一个页面任何一次http请求,增加对token过期的判断,如果token已过期,需要跳转至登录页面。如果要在每个页面中的http请求操作中添加一次判断,那么会是一个非常大的修改工作量。 vue-resource的interceptors拦截器的作用正是解决此需求的妙方。在每次http的请求响应之后,如果设置了拦截器如下,会优先执行拦截器函数,获取响应体,然后才会决定是否把response返回
Token 进行刷新续期,我们要解决并发请求导致重复刷新 Token 的问题,这也是设计刷新 Token 的难点。这里我会分别介绍前端和后端各自的处理方案。 后端方案:利用 Redis 缓存 当同时发起多个请求时,第一个接口刷新了 Token,后面的请求仍然能通过请求,且不造成 Token 重复刷新。那么,后端在用户第一次登录时,需要将生成的 Token 数据(token 和 createTime)缓存一份到 Redis 中。 当 Token 过期时,重新生成新的 Token 数据并更新 Redis 缓
保持登录的实现有很多,都有个自的优缺点,作为前端当然最喜欢后台注入cookie,后台自己管理session时效。这当然只是期望,还是很多用token和refresnToken的机制。 而管理token和刷新token就是一个问题了,比如判断过期时间到了去刷新token之后再请求,同时并发的请求你不能每个都去刷新一次token,只刷新一个,那并发的请求还是老的token。 解决的方法有两种,一种是请求之前处理,把同时并发的请求都挂起,用promise。这个方法不好的就是要新增白名单,那些不需要刷新token
post (target, params = {}) { let suffix = Object.keys(params).map(name => { return `${name}=${params[name]}` }).join('&') let urls = suffix.... const token = localStorage.getItem('token'); if (token) { config.headers.Authorization = `Bearer ${token}`; return config; error => { return Promise.reject(error); 其中,`localStorage.getItem('token')`是获取存储在本地的token,`config.headers.Authorization`是设置请求头中的Authorization字段,Bearer是一种常用的身份验证方式。 has been blocked by CORS policy: Request header field secret is not allowed by Access-Control-Allow- 19148 webstorm报错cliEngineCtor is not a constructor this.options.parse is not a function at ESLintPlugin CSDN-Ada助手: AI 写作助手上线啦!限免 4 天,快来创作试试功能吧~https://editor.csdn.net/md/?not_checkout=1&utmsource=blog_comment_recall 每日一题(十)function showCase(value){ switch(value){ case 'A': console.log('case m0_67135068: 还是不太懂表情包 echarts dataZoom 基本用法,给 yAxis 增加滚动条 软件园的肖邦: error: src refspec master does not match any error:failed to push some refs to 'git@github.com:xxxx pointer *: 多谢,有用!解了燃眉之急! webstorm报错cliEngineCtor is not a constructor this.options.parse is not a function at ESLintPlugin cezxktguml: 感谢up主,问题已经解决 webstorm报错cliEngineCtor is not a constructor this.options.parse is not a function at ESLintPlugin 前端项目中代码格式化配置:eslint + prettier + stylelint + pre-commit vue3 element-plus el-dialog 二次封装,多层调用