React-umi-request动态刷新Token功能实现及node.js 代码逻辑

在Antd-pro里面,使用的是umi-request,为了实现动态刷新token,我使用了拦截器。

拦截器更新token有两种:

方法一:在请求发起前拦截每个请求,判断token的有效时间是否已经过期,若已过期,则将请求挂起,先刷新token后再继续请求。

  • 优点: 在请求前拦截,能节省请求,省流量。
  • 缺点: 需要后端额外提供一个token过期时间的字段 refreshTime ;使用了本地时间判断,若本地时间被篡改,特别是本地时间比服务器时间慢时,拦截会失败。

方法二:拦截返回后的数据。先发起请求,接口返回过期后,先刷新token,再进行一次重试。

  • 优点:不需额外的token过期字段,不需判断时间。
  • 缺点: 会消耗多一次请求,耗流量。

综上考虑,方法一和二优缺点是互补的,方法一有校验失败的风险(本地时间被篡改时,当然一般没有用户闲的蛋疼去改本地时间的啦),方法二更简单粗暴,等知道服务器已经过期了再重试一次,只是会耗多一个请求。

我看有的博主用了方法二,我个人更喜欢方法一,(原因就是有的请求要求并发,for循环,一次出去10个请求,所以嘛。。。)

下面是实现过程

/**
 * request 网络请求工具
 * 更详细的 api 文档: https://github.com/umijs/umi-request
 */
import { extend } from ‘umi-request‘;
import { notification } from ‘antd‘;
import { routerRedux } from ‘dva/router‘;
import { getUserToken, saveUserToken, clearAuthority } from ‘./authority‘;
import jwt_decode from ‘jwt-decode‘
const codeMessage = {
  200: ‘服务器成功返回请求的数据。‘,
  201: ‘新建或修改数据成功。‘,
  202: ‘一个请求已经进入后台排队(异步任务)。‘,
  204: ‘删除数据成功。‘,
  400: ‘发出的请求有错误,服务器没有进行新建或修改数据的操作。‘,
  401: ‘用户没有权限(令牌、用户名、密码错误)。‘,
  403: ‘用户得到授权,但是访问是被禁止的。‘,
  404: ‘发出的请求针对的是不存在的记录,服务器没有进行操作。‘,
  406: ‘请求的格式不可得。‘,
  410: ‘请求的资源被永久删除,且不会再得到的。‘,
  422: ‘当创建一个对象时,发生一个验证错误。‘,
  500: ‘服务器发生错误,请检查服务器。‘,
  502: ‘网关错误。‘,
  503: ‘服务不可用,服务器暂时过载或维护。‘,
  504: ‘网关超时。‘,
};
/**
 * 异常处理程序
 */

const errorHandler = error => {
  const { response } = error;

  if (response && response.status) {
    const errorText = codeMessage[response.status] || response.statusText;
    const { status, url } = response;
    notification.error({
      message: `请求错误 ${status}: ${url}`,
      description: errorText,
    });
  } else if (!response) {
    notification.error({
      description: ‘您的网络发生异常,无法连接服务器‘,
      message: ‘网络异常‘,
    });
  }

  return response;
};
/**
 * 配置request请求时的默认参数
 */

const request = extend({
  errorHandler,
  // 默认错误处理
  credentials: ‘include‘, // 默认请求是否带上cookie
});

let _cacheRequest = [];
let guoqi = true;
let ispending = false;
request.interceptors.request.use(async (url, options) => {

    const token = getUserToken();
    if( token ){
        //如果有token 就走token逻辑
        const headers = {
            Authorization: `Bearer ${token}`,
        };
        //如果是刷新token接口,就直接过,不要拦截它!!!
        if( url === ‘/weiqinketop/api/account/login/getnewtoken‘){
            return ({
                url: url,
                options: { ...options, headers: headers },
            });
        }
        let decodeToken = jwt_decode(token);
        const { iat, exp, refreshTime } = decodeToken;
        const maxTime = exp*1000+refreshTime;
        const nowTime = new Date().getTime();
        console.log( parseInt((maxTime - nowTime)/1000) +‘秒后重新登录‘)
        if( nowTime >= maxTime){
            //token过期,而且延期token也过去了,那么,清空你的数据,直接返回登录,不允许操作了
            console.log(‘超时了‘)
            clearAuthority()
            location.href = ‘/user/login‘
            return;
        }
        console.log( parseInt((exp*1000 - nowTime)/1000) + ‘秒后第一个过期‘ )
        if( nowTime >= exp*1000 ){
            //只是过期了,那就去拿新的token
            if( ispending ){
                //如果正在发送中,此请求就等一会吧,生成一个Promise 等新token返回的时候,我再resolve
            }else{
                //如果没发送,立刻改为发送状态
                ispending = true;
                //如果过期了还没请求新token,那就请求新token 记得带上旧token
                request(‘/weiqinketop/api/account/login/getnewtoken‘,{
                    method: ‘POST‘,
                    data:{}
                }).then((res)=>{
                    if( res.status === 200 ){
                        ispending = false;
                        let token = res.token;
                        saveUserToken( token )
                        _cacheRequest.map(cb => cb())
                    }
                })

            }
            return new Promise((resolve, reject) => {
                _cacheRequest.push(() => {
                    resolve()
                })
            });
        }
        return ({
            url: url,
            options: { ...options, headers: headers },
        });
    }
    return ({
        url: url,
        options: options,
    });
})
//第二个拦截器,为什么会存在第二个拦截器呢?就是因为第一个拦截器有可能返回Promise,那么Promise由第二个拦截器处理吧。之前因为这个问题跟umi提了issues。原来是我没搞明白。。。
request.interceptors.request.use(async (url, options) => {
    const token = getUserToken();
    if( token ){
        //如果有token 就走token逻辑
        const headers = {
            Authorization: `Bearer ${token}`,
        };
        return ({
            url: url,
            options: { ...options, headers: headers },
        });
    }
    return ({
        url: url,
        options: options,
    });

})
export default request;

说下中途遇到的问题吧,原本只有第一个拦截器,返回Promise,总是会造成请求二次重发,我后来请教官方,得知 resolve( request( url, options) ) 导致的重发请求,现在已经进行了修复,可以正常使用了,后台使用的node.js KOA,下面贴下代码吧

/**** Token功能类 ****/
const jwt = require(‘jsonwebtoken‘);
/**** secret编码 ****/
const secret = ‘002c6‘;
/*****
 * 过期时间延长24小时
 */
// const refreshTime = 86400000;
/*****
 * 过期时间延长10s
 */
const refreshTime = 10000;

class Token{
     constructor() {
        this.jwt = jwt;
        this.secret = secret;
    }
    /*******生成的格式就是{alg: "HS256",typ: "JWT"}.{name: "你的名字字段",refreshTime: 10000,iat: 1573704935,exp: 1573704947.[signature] */
    createToken( payload , dateStr ){
        payload.refreshTime = refreshTime;
        return this.jwt.sign(payload, this.secret, { expiresIn: dateStr });
    }
}

// module.exports = {
//   proToken : new Token()
// }

exports.proToken = new Token()

原文地址:https://www.cnblogs.com/qkstart/p/11856168.html

时间: 2024-08-02 00:00:48

React-umi-request动态刷新Token功能实现及node.js 代码逻辑的相关文章

Angular、React.js 和Node.js到底选谁?

为了工作,程序员选择正确的框架和库来构建应用程序是至关重要的,这也就是为什么Angular和React之间有着太多的争议.Node.js的出现,让这场战争变得更加复杂,虽然有选择权通常是一件很棒的事情,但在这种情况下,对于到底应该选择哪种框架,程序员之间并没有一致的意见,每个人都有不同的想法,并且听起来都相当合理. 为了让一切归于和谐,本文就来探究一下这三大框架各自的优缺点. 基础知识部分: 在我们深入研究这三种框架的具体细节之前,先来了解一些前情提要.yigouyul22.com xucaiz

SOA中springmvc中restful服务动态刷新token信息

因为要考虑服务端token的动态刷新,而且还要单独启动定时调度任务去刷新token信息,保证token的时效及安全问题,直接分享动态刷新token的代码: Java代码 @CrossOrigin(origins = "*", maxAge = 3600,methods={RequestMethod.GET,RequestMethod.POST,RequestMethod.DELETE,RequestMethod.PUT}) @RestController @RequestMapping

request.getContextPath()的功能

<% String contextPath = request.getContextPath();  // 得到项目的名字 com.chint.until.SessionInfo sessionInfo = (com.chint.until.SessionInfo) session.getAttribute("sessionInfo"); %> 在JSP中有html.js.java这三种语言,其中的java,被称之为java代码片段,<%  java代码片段 %>

Electron + React + Node.js + ES6 开发本地 App

Electron + React + Node.js + ES6 开发本地 App 1.概述 近来工作上需要做一款 PC 上的软件,这款软件大体来讲是类似 PPT 的一款课件制作软件.由于我最近几年专注于移动 App 的开发,对 PC 端开发的了解有些滞后.所以我首先需要看看,在 PC 上采用什么框架能够顺利完成我的工作. 我的目标是,在完成这款软件的同时能够顺便学习一下比较流行的技术.在经过前期技术调研后,我明确了实现这款软件所需要的技术条件: 不采用 C++ 方面的类库,比如 MFC.Qt.

node.js实现CURL功能

PHP中的CURL功能很好实现,直接四五行代码封装一下就OK了.node.js中如何实现CURL的功能呢,下面详细介绍. 这里需要用到request这个库,所以先安装此包: npm install request 安装下来之后, 就是代码实现的问题了.示例代码如下(只实现了POST方法): var request = require('request'); request.post( { url:'http://hovertree.com:9095/phpTest.php', form:{ us

Request —— 让 Node.js http请求变得超简单

先前一直比较关注前端的东西,对后端了解较少.不过一直对Node.js比较感兴趣,去年12月还去参加了阿里的CNODE交流聚会. 以后希望通过这里的博客分享一些学习Node.js的笔记.一方面总结了自己的学习心得,另一方面也可以和大家一起分享交流. 嗯,大概就是这样子. 这篇就先介绍一个Node.js的模块——request.有了这个模块,http请求变的超简单. 使用超简单 Request使用超简单,同时支持https和重定向. var request = require('request');

00微信公众平台 - 以上五大功能整合,完整的代码。

一.代码实现如下(主程序代码,其他include代码见各个功能函数中) <?php /** * wechat php test * version 1 */ define("TOKEN", "weixin"); $wechatObj = new wechatCallbackapiTest(); $wechatObj->responseMsg(); //$wechatObj->valid(); class wechatCallbackapiTest

node.js学习笔记之React

React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC 框架,都不满意,就决定自己写一套,用来架设 Instagram 的网站.做出来以后,发现这套东西很好用,就在2013年5月开源了.由于 React 的设计思想极其独特,属于革命性创新,性能出众,代码逻辑却非常简单.所以,越来越多的人开始关注和使用,认为它可能是将来 Web 开发的主流工具. ReactJS官网地址:http://facebook.github.io/react/ Github地

node.js学习(2)--路由功能以及表单上传

今天按照<node.js入门>这本书学习了node的一些基础知识,包括服务器的创建,路由功能的实现,表单上传和数据处理,感觉开始明白了node.js的一些基本原理.这本书说的很详细也很基础,很适合初学者学习.node.js入门 众所周知,node跟php语言不一样,node不需要依赖于apache等服务器,因为node本身就能够构建服务器!所以,再用node开发网站之前我们首先得学会如何搭建服务器.关于node创建服务器在我之前的博客已经有介绍,这里不再赘述. 完成一个表单上传与数据处理的de