ref : 重构令牌管理逻辑,,统一状态码识别
This commit is contained in:
@@ -1,25 +1,45 @@
|
||||
import Cookies from 'js-cookie';
|
||||
import { TOKEN_COOKIE } from '@/constants/token-constants';
|
||||
import { localRemove, localSet } from '@/utils/cache-local-utils';
|
||||
import {
|
||||
CACHE_LOCAL_LOCK_PASSWD,
|
||||
CACHE_LOCAL_MASK,
|
||||
} from '@/constants/cache-keys-constants';
|
||||
TOKEN_ACCESS_COOKIE,
|
||||
TOKEN_REFRESH_COOKIE,
|
||||
} from '@/constants/token-constants';
|
||||
|
||||
/**获取cookis中Token字符串 */
|
||||
export function getToken(): string {
|
||||
return Cookies.get(TOKEN_COOKIE) || '';
|
||||
/**获取访问令牌 */
|
||||
export function getAccessToken(): string {
|
||||
return Cookies.get(TOKEN_ACCESS_COOKIE) || '';
|
||||
}
|
||||
|
||||
/**设置cookis中Token字符串 */
|
||||
export function setToken(token: string): void {
|
||||
Cookies.set(TOKEN_COOKIE, token || '');
|
||||
localSet(CACHE_LOCAL_MASK, 'none');
|
||||
/**
|
||||
* 设置访问令牌
|
||||
* @param token token字符串
|
||||
* @param exp 过期时间(秒)
|
||||
*/
|
||||
export function setAccessToken(token: string, exp: number): void {
|
||||
const expires = new Date(new Date().getTime() + exp * 1000);
|
||||
Cookies.set(TOKEN_ACCESS_COOKIE, token, { expires });
|
||||
}
|
||||
|
||||
/**移除cookis中Token字符串,localStorage中锁屏字符串 */
|
||||
export function removeToken(): void {
|
||||
Cookies.remove(TOKEN_COOKIE);
|
||||
localRemove(CACHE_LOCAL_MASK);
|
||||
localRemove(CACHE_LOCAL_LOCK_PASSWD);
|
||||
/**移除访问令牌 */
|
||||
export function delAccessToken(): void {
|
||||
Cookies.remove(TOKEN_ACCESS_COOKIE);
|
||||
}
|
||||
|
||||
/**获取刷新令牌 */
|
||||
export function getRefreshToken(): string {
|
||||
return Cookies.get(TOKEN_REFRESH_COOKIE) || '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置刷新令牌
|
||||
* @param token token字符串
|
||||
* @param exp 过期时间(秒)
|
||||
*/
|
||||
export function setRefreshToken(token: string, exp: number): void {
|
||||
const expires = new Date(new Date().getTime() + exp * 1000);
|
||||
Cookies.set(TOKEN_REFRESH_COOKIE, token, { expires });
|
||||
}
|
||||
|
||||
/**移除刷新令牌 */
|
||||
export function delRefreshToken(): void {
|
||||
Cookies.remove(TOKEN_REFRESH_COOKIE);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
import { getToken, removeToken } from '@/plugins/auth-token';
|
||||
import {
|
||||
getAccessToken,
|
||||
setAccessToken,
|
||||
delAccessToken,
|
||||
getRefreshToken,
|
||||
setRefreshToken,
|
||||
delRefreshToken,
|
||||
} from '@/plugins/auth-token';
|
||||
import {
|
||||
sessionGet,
|
||||
sessionGetJSON,
|
||||
sessionSetJSON,
|
||||
} from '@/utils/cache-session-utils';
|
||||
import { localGet } from '@/utils/cache-local-utils';
|
||||
import { TOKEN_KEY, TOKEN_KEY_PREFIX } from '@/constants/token-constants';
|
||||
import {
|
||||
CACHE_LOCAL_I18N,
|
||||
@@ -18,6 +24,7 @@ import {
|
||||
import {
|
||||
RESULT_CODE_ENCRYPT,
|
||||
RESULT_CODE_ERROR,
|
||||
RESULT_CODE_EXCEPTION,
|
||||
RESULT_CODE_SUCCESS,
|
||||
RESULT_MSG_ENCRYPT,
|
||||
RESULT_MSG_ERROR,
|
||||
@@ -25,10 +32,11 @@ import {
|
||||
RESULT_MSG_SERVER_ERROR,
|
||||
RESULT_MSG_SUCCESS,
|
||||
RESULT_MSG_TIMEOUT,
|
||||
RESULT_MSG_URL_NOTFOUND,
|
||||
RESULT_MSG_URL_RESUBMIT,
|
||||
} from '@/constants/result-constants';
|
||||
import { decryptAES, encryptAES } from '@/utils/encrypt-utils';
|
||||
import { localGet } from '@/utils/cache-local-utils';
|
||||
import { refreshToken } from '@/api/auth';
|
||||
|
||||
/**响应结果类型 */
|
||||
export type ResultType = {
|
||||
@@ -61,7 +69,7 @@ type OptionsType = {
|
||||
/**请求地址 */
|
||||
url: string;
|
||||
/**请求方法 */
|
||||
method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
||||
method: 'GET' | 'POST' | 'PUT' | 'DELETE';
|
||||
/**请求头 */
|
||||
headers?: HeadersInit;
|
||||
/**地址栏参数 */
|
||||
@@ -133,16 +141,21 @@ function beforeRequest(options: OptionsType): OptionsType | Promise<any> {
|
||||
Reflect.set(options.headers, 'Accept-Language', `${language};q=0.9`);
|
||||
|
||||
// 是否需要设置 token
|
||||
const token = getToken();
|
||||
if (options.whithToken && token) {
|
||||
Reflect.set(options.headers, TOKEN_KEY, TOKEN_KEY_PREFIX + token);
|
||||
const accessToken = getAccessToken();
|
||||
if (options.whithToken && accessToken) {
|
||||
Reflect.set(
|
||||
options.headers,
|
||||
TOKEN_KEY,
|
||||
TOKEN_KEY_PREFIX + ' ' + accessToken
|
||||
);
|
||||
}
|
||||
|
||||
// 是否需要防止数据重复提交
|
||||
if (
|
||||
options.repeatSubmit &&
|
||||
options.dataType === 'json' &&
|
||||
['post', 'put'].includes(options.method)
|
||||
!(options.data instanceof FormData) &&
|
||||
['POST', 'PUT'].includes(options.method)
|
||||
) {
|
||||
const requestObj: RepeatSubmitType = {
|
||||
url: options.url,
|
||||
@@ -212,13 +225,31 @@ function beforeRequest(options: OptionsType): OptionsType | Promise<any> {
|
||||
return options;
|
||||
}
|
||||
|
||||
/**请求后的拦截 */
|
||||
function interceptorResponse(res: ResultType): ResultType | Promise<any> {
|
||||
/**响应前的拦截 */
|
||||
async function beforeResponse(
|
||||
options: OptionsType,
|
||||
res: ResultType
|
||||
): Promise<any> {
|
||||
// console.log('请求后的拦截', res);
|
||||
|
||||
// 登录失效时,移除授权令牌并重新刷新页面
|
||||
if (res.code === 401) {
|
||||
removeToken();
|
||||
// 登录失效时,移除访问令牌并重新请求
|
||||
if (res.code === 401001) {
|
||||
const result = await refreshToken(getRefreshToken());
|
||||
// 更新访问令牌和刷新令牌
|
||||
if (result.code === RESULT_CODE_SUCCESS) {
|
||||
setAccessToken(result.data.accessToken, result.data.refreshExpiresIn);
|
||||
setRefreshToken(result.data.refreshToken, result.data.refreshExpiresIn);
|
||||
return await request(options);
|
||||
} else {
|
||||
delAccessToken();
|
||||
delRefreshToken();
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
if ([401002, 401003].includes(res.code)) {
|
||||
delAccessToken();
|
||||
delRefreshToken();
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
@@ -271,43 +302,45 @@ function interceptorResponse(res: ResultType): ResultType | Promise<any> {
|
||||
* @returns 返回 Promise<ResultType>
|
||||
*/
|
||||
export async function request(options: OptionsType): Promise<ResultType> {
|
||||
options = Object.assign({}, FATCH_OPTIONS, options);
|
||||
let timeoutId: any = 0;
|
||||
let reqOptions = Object.assign({}, FATCH_OPTIONS, options);
|
||||
|
||||
// 请求超时控制请求终止
|
||||
if (!options.signal) {
|
||||
let timeoutId: any = null;
|
||||
if (!reqOptions.signal) {
|
||||
const controller = new AbortController();
|
||||
const { signal } = controller;
|
||||
options.signal = signal;
|
||||
reqOptions.signal = controller.signal;
|
||||
timeoutId = setTimeout(() => {
|
||||
controller.abort(); // 终止请求
|
||||
}, options.timeout);
|
||||
}, reqOptions.timeout);
|
||||
}
|
||||
|
||||
// 检查请求拦截
|
||||
const beforeReq = beforeRequest(options);
|
||||
const beforeReq = beforeRequest(reqOptions);
|
||||
if (beforeReq instanceof Promise) {
|
||||
return await beforeReq;
|
||||
}
|
||||
options = beforeReq;
|
||||
reqOptions = beforeReq;
|
||||
|
||||
// 判断用户传递的URL是否http或/开头
|
||||
if (!options.url.startsWith('http')) {
|
||||
const uri = options.url.startsWith('/') ? options.url : `/${options.url}`;
|
||||
options.url = options.baseUrl + uri;
|
||||
if (!reqOptions.url.startsWith('http')) {
|
||||
const uri = reqOptions.url.startsWith('/')
|
||||
? reqOptions.url
|
||||
: `/${reqOptions.url}`;
|
||||
reqOptions.url = reqOptions.baseUrl + uri;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch(options.url, options);
|
||||
const res = await fetch(reqOptions.url, reqOptions);
|
||||
// console.log('请求结果:', res);
|
||||
|
||||
// 状态码拦截处理
|
||||
const reqNot = stateCode(res);
|
||||
if (reqNot != false) {
|
||||
return reqNot;
|
||||
if (res.status === 500) {
|
||||
return {
|
||||
code: RESULT_CODE_EXCEPTION,
|
||||
msg: RESULT_MSG_SERVER_ERROR[language],
|
||||
};
|
||||
}
|
||||
|
||||
// 根据响应数据类型返回
|
||||
switch (options.responseType) {
|
||||
switch (reqOptions.responseType) {
|
||||
case 'text': // 文本数据
|
||||
const str = await res.text();
|
||||
return {
|
||||
@@ -317,11 +350,7 @@ export async function request(options: OptionsType): Promise<ResultType> {
|
||||
case 'json': // json格式数据
|
||||
const result = await res.json();
|
||||
// 请求后的拦截
|
||||
const beforeRes = interceptorResponse(result);
|
||||
if (beforeRes instanceof Promise) {
|
||||
return await beforeRes;
|
||||
}
|
||||
return result;
|
||||
return await beforeResponse(options, result);
|
||||
case 'blob': // 二进制数据则直接返回
|
||||
case 'arrayBuffer':
|
||||
const contentType = res.headers.get('content-type') || '';
|
||||
@@ -330,7 +359,7 @@ export async function request(options: OptionsType): Promise<ResultType> {
|
||||
return result as ResultType;
|
||||
}
|
||||
const data =
|
||||
options.responseType === 'blob'
|
||||
reqOptions.responseType === 'blob'
|
||||
? await res.blob()
|
||||
: await res.arrayBuffer();
|
||||
return {
|
||||
@@ -356,41 +385,7 @@ export async function request(options: OptionsType): Promise<ResultType> {
|
||||
}
|
||||
throw error;
|
||||
} finally {
|
||||
clearTimeout(timeoutId); // 请求成功,清除超时计时器
|
||||
clearTimeout(timeoutId); // 清除超时计时器
|
||||
timeoutId = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断状态码处理结果信息(不可处理)
|
||||
* @param res 请求结果
|
||||
* @returns
|
||||
*/
|
||||
function stateCode(res: Response) {
|
||||
// 网络异常
|
||||
if (res.status === 500) {
|
||||
return {
|
||||
code: RESULT_CODE_ERROR,
|
||||
msg: RESULT_MSG_SERVER_ERROR[language],
|
||||
};
|
||||
}
|
||||
// 上传文件成功无内容返回
|
||||
if (res.status === 204 || res.statusText === 'No Content') {
|
||||
return {
|
||||
code: RESULT_CODE_SUCCESS,
|
||||
msg: RESULT_MSG_SUCCESS[language],
|
||||
};
|
||||
}
|
||||
// 地址找不到
|
||||
if (res.status === 404 || res.status === 405) {
|
||||
return {
|
||||
code: RESULT_CODE_ERROR,
|
||||
msg: RESULT_MSG_URL_NOTFOUND[language],
|
||||
};
|
||||
}
|
||||
// 身份授权
|
||||
if (res.status === 401) {
|
||||
removeToken();
|
||||
window.location.reload();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { sessionGet } from '@/utils/cache-session-utils';
|
||||
import { getToken } from './auth-token';
|
||||
import { getAccessToken } from './auth-token';
|
||||
import { localGet } from '@/utils/cache-local-utils';
|
||||
import { CACHE_LOCAL_I18N } from '@/constants/cache-keys-constants';
|
||||
import { TOKEN_RESPONSE_FIELD } from '@/constants/token-constants';
|
||||
@@ -92,7 +92,7 @@ export class WS {
|
||||
// 地址栏参数
|
||||
let params = Object.assign({}, options.params, {
|
||||
// 设置 token
|
||||
[TOKEN_RESPONSE_FIELD]: getToken(),
|
||||
[TOKEN_RESPONSE_FIELD]: getAccessToken(),
|
||||
// 多语言
|
||||
['language']: localGet(CACHE_LOCAL_I18N) || 'en_US',
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user