当前位置: 首页 > news >正文

网站空间购买自己没有产品

网站空间购买,自己没有产品,如何确认建设银行网站不是假的,电子商务网站建设交印花税吗文章目录 背景基本思路需解决的问题请求进入死循环标记刷新 token 请求避免请求拦截覆盖 refresh token并发刷新 token 完整代码注意#xff1a;拦截器注册顺序另一种方案#xff1a;事件驱动刷新 前景提要#xff1a; ts 简易封装 axios#xff0c;统一 API 实现在 confi… 文章目录 背景基本思路需解决的问题请求进入死循环标记刷新 token 请求避免请求拦截覆盖 refresh token并发刷新 token 完整代码注意拦截器注册顺序另一种方案事件驱动刷新 前景提要 ts 简易封装 axios统一 API 实现在 config 中配置开关拦截器 axios 实现请求 loading 效果 背景 无感刷新 token 一般指的是使用 refresh token 无感刷新 access token。 基本思路 设置全局请求拦截器从 localstorage 或其他地方获取 token 放在请求头中携带。在响应拦截器中判断响应结果中是否有 token有就存下来放在 localstorage 或其他地方。 一句话总结就是本地有就带响应有就存。 实现自动刷新就是在响应拦截之前的基础上再加一个判断如果 access token 过期了就携带 refresh token 去请求认证中心的接口。拿到新的 access token 后再次对业务接口发起请求。 注意别忘了要让新业务请求携带最新的 access token。 在axios拦截器中重新发起请求就是拿到业务请求的 config用axios实例发起请求。所以也可以说一个请求的本质就是它的config配置对象。 src\api\http\token.ts import { AxiosResponse, InternalAxiosRequestConfig } from axios; import httpRequest from ..; import { refreshAccessToken } from ../modules/refreshToken;export const ACCESS_TOKEN_KEY access_token; export const REFRESH_TOKEN_KEY refresh_token; export const UNAUTHORIZED_STATUS_CODE 401;// token 工具函数/*** 获取token* param key token的key* returns {string}accessToken*/ export function getToken(key: string) {return localStorage.getItem(key); }/*** 存储token到本地* param key token的key* param token token的值*/ export function setToken(key: string, token: string) {localStorage.setItem(key, token); }// 拦截器/*** 请求拦截器只要本地有access token所有请求的请求头就携带上它。(对于没有采用单点登录方案的系统access token就是普通 token)* param {InternalAxiosRequestConfig}config* returns {InternalAxiosRequestConfig}config*/ export function setAccessTokenRequestInterceptor(config: InternalAxiosRequestConfig) {if (config.headers) config.headers.authorization Bearer ${getToken(accessToken)};return config; }/*** 响应拦截器只要服务器响应了 token就保存下来到本地无论是 access token 还是 refresh token。* 当接口因权限拒绝或者本地计算 access token 过期则就去拿 refresh token 无感刷新 access token。* param {AxiosResponse}res* returns {AxiosResponse}res*/ export async function getTokenResponseInterceptor(res: AxiosResponse) {// 假设服务器将token放在响应头中返回// 保存授权 token也就是 access token 或者普通的 tokenif (res.headers.authorization) {const token res.headers.authorization.repalce(Bearer , );setToken(ACCESS_TOKEN_KEY, token);}// 保存 refresh tokenif (res.headers.refreshtoken) {const refreshToken res.headers.refreshtoken.repalce(Bearer , );setToken(REFRESH_TOKEN_KEY, refreshToken);}// 请求业务接口没有权限说明 access token 过期需要刷新 tokenif (res.data.code UNAUTHORIZED_STATUS_CODE) {// 请求服务器获取最新access token当前拦截器递归保存tokenconst isRefreshSuccess await refreshAccessToken();if (isRefreshSuccess) {// 刷新 access token 成功装配新 access token 后拿到 axios 实例重新发起请求res.config.headers.Authorization Bearer ${getToken(ACCESS_TOKEN_KEY)};const response await httpRequest.getInstance().request(res.config);return response;} else {// 刷新失败refresh token 过期跳转登录页面重新登录window.location.hash /login;// window.location.href /login;}}return res; } src\api\modules\refreshToken.ts import httpRequest from ..; import { REFRESH_TOKEN_KEY, UNAUTHORIZED_STATUS_CODE, getToken } from ../http/token;const REFRESH_TOKEN_API /refreshToken;/*** 获取 refresh token 的接口* 这个接口不同于业务接口它携带的 token 是 refresh token 而不是 access token。* 当请求 access token 回来后就会启动响应拦截将 access token 保存* 返回一个布尔值用于判断是否刷新成功因为 refresh token 也会过期导致刷新失败。* returns {boolean} isRefreshSuccess 刷新 access token 是否成功。*/ export async function refreshAccessToken() {const res await httpRequest.get({url: REFRESH_TOKEN_API,headers: {Authorization: Bearer ${getToken(REFRESH_TOKEN_KEY)}}});// 响应状态码不为 401则表示刷新成功return res.code ! UNAUTHORIZED_STATUS_CODE; } 需解决的问题 请求进入死循环 假如 refresh token 也过期了那么携带 refresh token 去刷新 access token时就会被拒绝refreshAccessToken 请求失败状态码 401。这时因为是 401响应拦截器中就又会以为是 access token 过期又拿着 refresh token 去刷新。至此陷入死循环了。 核心就是当前是否启动无感刷新 access token 的判断条件需要区分是 access token 过期导致的业务接口拒绝还是 refresh token 过期导致的授权接口拒绝。 解决办法可以是服务器接口给出过期时间或者前端自己解析 jwt拿到过期时间。然后通过判断 access token 过期时间来选择是否要去刷新。 假如通过接口返回 401 来判断。这时可以引入一个变量做标志表明当前请求是否是刷新 access token 的请求还是业务请求。 src\api\modules\refreshToken.ts export async function refreshAccessToken() {const res await httpRequest.get({url: REFRESH_TOKEN_API,headers: {Authorization: Bearer ${getToken(REFRESH_TOKEN_KEY)},_isRefreshAccessTokenRequest: true // 标记当前请求为刷新 token 请求}});return res.code ! UNAUTHORIZED_STATUS_CODE; } src\api\http\token.ts // 请求业务接口没有权限说明 access token 过期需要刷新 token if (res.data.code UNAUTHORIZED_STATUS_CODE !res.config.headers._isRefreshAccessTokenRequest) {// 请求服务器获取最新access token当前拦截器递归保存tokenconst isRefreshSuccess await refreshAccessToken();if (isRefreshSuccess) {// 刷新 access token 成功装配新 access token 后拿到 axios 实例重新发起请求res.config.headers.Authorization Bearer ${getToken(ACCESS_TOKEN_KEY)};const response await httpRequest.getInstance().request(res.config);return response;} else {// 刷新失败refresh token 过期跳转登录页面重新登录window.location.hash /login;// window.location.href /login;} }标记刷新 token 请求避免请求拦截覆盖 refresh token 刷新 access token 的请求也是一个请求它携带的是 refresh token。但是之前我们设置了全局的请求拦截器。又因为无论是 access token 还是 refresh token 都是放在请求头的 authorization 上携带此时请求拦截设置的 access token 就会覆盖掉 refresh token导致刷新接口拿不到 refresh token。 因此请求拦截器也要对刷新 token 的请求做额外的区分过滤掉刷新请求。也可以通过请求头的标记实现。 export function setAccessTokenRequestInterceptor(config: InternalAxiosRequestConfig) {if (config.headers !config.headers._isRefreshAccessTokenRequest) {config.headers.authorization Bearer ${getToken(ACCESS_TOKEN_KEY)};}return config; }并发刷新 token 如果当前有很多业务请求然后 access token 刚好过期了。那这些业务请求的响应拦截器中都会拿着 refresh token 去请求刷新接口刷新 access token。前一个刷新请求还没拿到最新的 access token后一个刷新请求又发出了这就出现了并发刷新 token 冗余发送请求的情况。 解决这个问题的核心无非就是确定上一个刷新 token 的请求是否结束它没结束后续的刷新请求就得等着。这种观测异步处理的状态promise 干的就是这个。 定义一个全局的变量用这个全局的变量保存刷新 token 的请求也就是保存一个 promise。 变量初始是空的因为没有刷新请求。当有刷新请求发起就生成一个 promise 观测该请求并将该 promise 保存在全局变量中。此时后续想要再次发起刷新请求就直接返回这个“全局的请求”promise给它们避免了发起冗余请求。并且这样当第一个刷新请求得到结果后续所有请求就都拿到了结果因为都是同一个 promise。 promise 有结果后无论刷新成功与否都代表了本轮并发刷新 token 请求的结束需将全局变量重置为 null以准备下一次并发刷新请求。 import httpRequest from ..; import { REFRESH_TOKEN_KEY, UNAUTHORIZED_STATUS_CODE, getToken } from ../http/token;const REFRESH_TOKEN_API /refreshtoken;let promise: Promiseany | null null;/*** 获取 refresh token 的接口* 这个接口不同于业务接口它携带的 token 是 refresh token 而不是 access token。* 当请求 access token 回来后就会启动响应拦截将 access token 保存* 返回一个 Promise 布尔值用于判断是否刷新成功因为 refresh token 也会过期导致刷新失败。* returns {Promiseboolean} isRefreshSuccess 刷新 access token 是否成功。*/ export function refreshAccessToken() {// 前面已经发送了刷新请求promise 有值此时后续请求全都返回最开始的 promiseif (promise) {return promise;}promise new Promise((resolve, rejects) {httpRequest.get({url: REFRESH_TOKEN_API,headers: {Authorization: Bearer ${getToken(REFRESH_TOKEN_KEY)},_isRefreshAccessTokenRequest: true}}).then(res {resolve(res.code ! UNAUTHORIZED_STATUS_CODE);}).catch(() rejects(false)).finally(() {promise null; // 本次并发刷新请求结束重置变量为 null});});return promise; }完整代码 src\api\http\token.ts import { AxiosResponse, InternalAxiosRequestConfig } from axios; import httpRequest from ..; import { refreshAccessToken } from ../modules/refreshToken;export const ACCESS_TOKEN_KEY access_token; export const REFRESH_TOKEN_KEY refresh_token; export const UNAUTHORIZED_STATUS_CODE 401;// token 工具函数/*** 获取token* param key token的key* returns {string}accessToken*/ export function getToken(key: string) {return localStorage.getItem(key); }/*** 存储token到本地* param key token的key* param token token的值*/ export function setToken(key: string, token: string) {localStorage.setItem(key, token); }// 拦截器/*** 请求拦截器只要本地有access token所有请求的请求头就携带上它。(对于没有采用单点登录方案的系统access token就是普通 token)* param {InternalAxiosRequestConfig}config* returns {InternalAxiosRequestConfig}config*/ export function setAccessTokenRequestInterceptor(config: InternalAxiosRequestConfig) {if (config.headers !config.headers._isRefreshAccessTokenRequest) {config.headers.authorization Bearer ${getToken(ACCESS_TOKEN_KEY)};}return config; }/*** 响应拦截器只要服务器响应了 token就保存下来到本地无论是 access token 还是 refresh token。* 当接口因权限拒绝或者本地计算 access token 过期则就去拿 refresh token 无感刷新 access token。* param {AxiosResponse}res* returns {AxiosResponse}res*/ export async function getTokenResponseInterceptor(res: AxiosResponse) {// 假设服务器将token放在响应体中返回// 保存授权 token也就是 access token 或者普通的 tokenif (res.data.data?.accessToken) {const token res.data.data.accessToken.replace(Bearer , );setToken(ACCESS_TOKEN_KEY, token);}// 保存 refresh tokenif (res.data.data?.refreshToken) {const refreshToken res.data.data.refreshToken.replace(Bearer , );setToken(REFRESH_TOKEN_KEY, refreshToken);}// 请求业务接口没有权限说明 access token 过期需要刷新 tokenif (res.data.code UNAUTHORIZED_STATUS_CODE !res.config.headers._isRefreshAccessTokenRequest) {// 请求服务器获取最新access token当前拦截器递归保存tokenconst isRefreshSuccess await refreshAccessToken();if (isRefreshSuccess) {// 刷新 access token 成功装配新 access token 后拿到 axios 实例重新发起请求res.config.headers.Authorization Bearer ${getToken(ACCESS_TOKEN_KEY)};const response await httpRequest.getInstance().request(res.config);return response;} else {// 刷新失败refresh token 过期跳转登录页面重新登录window.location.hash /login;// window.location.href /login;}}return res; } src\api\modules\refreshToken.ts import httpRequest from ..; import { REFRESH_TOKEN_KEY, UNAUTHORIZED_STATUS_CODE, getToken } from ../http/token;const REFRESH_TOKEN_API /refreshtoken;let promise: Promiseany | null null;/*** 获取 refresh token 的接口* 这个接口不同于业务接口它携带的 token 是 refresh token 而不是 access token。* 当请求 access token 回来后就会启动响应拦截将 access token 保存* 返回一个 Promise 布尔值用于判断是否刷新成功因为 refresh token 也会过期导致刷新失败。* returns {Promiseboolean} isRefreshSuccess 刷新 access token 是否成功。*/ export function refreshAccessToken() {// 前面已经发送了刷新请求promise 有值此时后续请求全都返回最开始的 promiseif (promise) {return promise;}promise new Promise((resolve, rejects) {httpRequest.get({url: REFRESH_TOKEN_API,headers: {Authorization: Bearer ${getToken(REFRESH_TOKEN_KEY)},_isRefreshAccessTokenRequest: true}}).then(res {resolve(res.code ! UNAUTHORIZED_STATUS_CODE);}).catch(() rejects(false)).finally(() {promise null; // 本次并发刷新请求结束重置变量为 null});});return promise; } 测试代码 templatedivh2测试无感刷新 token/h2el-button typeprimary round clickhandleClickLogin登录/el-buttonel-button typeprimary round clickhandleClickGetProtectData请求受保护资源/el-button/div /templatescript setup langtsimport { login } from /api/modules/login;import { fetchUsersList } from /api/modules/user;const handleClickLogin () {login({ username: admin }).then(res {console.log(res);});};const handleClickGetProtectData async () {const res await fetchUsersList();console.log(res, res);}; /scriptstyle scoped/style 注意拦截器注册顺序 注册无感刷新的响应拦截器要在防抖拦截器的后面。 如这样 // debounceRequest httpRequest.getInstance().interceptors.request.use(compareUrl); httpRequest.getInstance().interceptors.response.use(filterFulfilledUrl);// token httpRequest.getInstance().interceptors.request.use(setAccessTokenRequestInterceptor); httpRequest.getInstance().interceptors.response.use(getTokenResponseInterceptor);请求防抖是通过比较请求 url 来实现的。在请求拦截器中保存当前请求的url到数组中后续的请求都需要判断一下当前请求的url是否已经在数组中。当响应拦截器启动说明请求完毕就从数组中清除此url。 此时问题就来了假如 token 的响应拦截定义在防抖响应拦截器的前面。axios响应拦截越晚定义越晚执行 当 access token 过期token 响应拦截器中会去刷新 token并对业务接口重新发起请求。注意此时仍然处于上一次被拒绝请求的拦截器中。那后续的防抖响应拦截器肯定还没执行也就是还没有清除数组中被拒绝请求的url。此时又重新发送了请求防抖的请求拦截中就会发挥防抖功能抛出错误“请求频繁。 因此防抖响应拦截器和无感刷新 token 的响应拦截器有注册顺序token 拦截要后注册。 另一种方案事件驱动刷新 这种方式以某个页面事件触发刷新而不是在拦截器中判断所有请求的结果。 用户登陆返回accesTokenrefreshToken 还有accesToken有效时间戳。 每次加载到home页面直接判断accesToken是否过期过期了直接用refreshToken请求刷新accesToken接口返回新的accesToken新的refreshTokenaccesToken的有效时间戳。 accesToken的有效时间戳并不是accesToken真正失效时间一般会比真的失效时间点会提前的。 至于其他request和这套机制完全独立的。只是每次请求带上accessToken罢了。不用考虑accesToken过期啥的。
http://www.hkea.cn/news/14469561/

相关文章:

  • 网站备案查询 优帮云wordpress批量替换代码
  • 安徽省建设安全监督站的网站商城app搭建
  • 网站正在建设中 htmll全景网站app
  • 一个网站可以做几个关键词江门网站设计价格
  • 电子商务网站建设答辩记录wordpress第三方客户端
  • 建网站做代理ip建设网站建设方案
  • 欧美网站特点免费psd模板素材
  • 英文网站建设官网网页制作属于前端吗
  • 深圳网站优化公司哪家好长沙找工作哪个网站好
  • 网站一般用什么做的做二手平台公益的网站
  • 常见的电子商务网站有哪些发免费广告电话号码
  • 电商网站建设综述网站域名过期怎么办
  • 易语言做购物网站长安网站建设免费咨询
  • 基于php技术的个人网站设计wordpress魔客模板
  • 网站上一页下一页怎么做定制一个软件要多少钱
  • IT男做网站wordpress会员等级查看文章
  • 怎么样免费做自己的网站百度seo优化技巧
  • 凡科自助建站自己做网站做违规网站
  • 什么是网站建设有哪些具体内容中山网站建设华联在线
  • 封开网站建设wordpress cms下载地址
  • 如何让域名指向网站湛江网站建设方案书
  • 普通网站建设多少钱logo设计公司企业
  • 做网站设计多少钱即刻搜索收录网站
  • 网站开发好后版权归谁常德论坛尚一网
  • 洛卡博网站谁做的做网站用什么插件
  • 皮肤自做头像的网站网店如何推广
  • 商业网站后缀名网址是什么
  • 文章内容网站系统网站目标关键词
  • 锦州如何做百度的网站网站建设首选
  • 百度站内搜索提升关键词排名新型网站建设