mirror of https://github.com/msgbyte/tailchat
refactor: login request
parent
6a0852123a
commit
f99297ce68
@ -0,0 +1,62 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
import _get from 'lodash/get';
|
||||||
|
import _isString from 'lodash/isString';
|
||||||
|
import _isNil from 'lodash/isNil';
|
||||||
|
import _isFunction from 'lodash/isFunction';
|
||||||
|
import { config } from '../config';
|
||||||
|
import { getErrorHook, tokenGetter } from '../manager/request';
|
||||||
|
|
||||||
|
export type CommonRequestResult<T> =
|
||||||
|
| ({
|
||||||
|
result: false;
|
||||||
|
msg: string;
|
||||||
|
} & Partial<T>) // 并上一个T是为了方便取值, 但需要判定
|
||||||
|
| ({
|
||||||
|
result: true;
|
||||||
|
} & T);
|
||||||
|
|
||||||
|
class RequestError extends Error {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建请求实例
|
||||||
|
*/
|
||||||
|
export function createRequest() {
|
||||||
|
const ins = axios.create({
|
||||||
|
baseURL: config.serverUrl,
|
||||||
|
});
|
||||||
|
|
||||||
|
ins.interceptors.request.use(async (val) => {
|
||||||
|
if (
|
||||||
|
['post', 'get'].includes(String(val.method).toLowerCase()) &&
|
||||||
|
!val.headers['X-Token']
|
||||||
|
) {
|
||||||
|
// 任何请求都尝试增加token
|
||||||
|
val.headers['X-Token'] = await tokenGetter();
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
});
|
||||||
|
|
||||||
|
ins.interceptors.response.use(
|
||||||
|
(val) => {
|
||||||
|
return val;
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
// 尝试获取错误信息
|
||||||
|
const errorMsg: string = _get(err, 'response.data.message');
|
||||||
|
const code: number = _get(err, 'response.data.code');
|
||||||
|
if (_isFunction(getErrorHook)) {
|
||||||
|
const isContinue = getErrorHook(err);
|
||||||
|
if (isContinue === false) {
|
||||||
|
return { data: { result: false, msg: errorMsg, code } };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new RequestError(errorMsg ?? err.message);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return ins;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const request = createRequest();
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* Pawchat 共享配置
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const config = {
|
||||||
|
serverUrl: 'http://127.0.0.1:11000',
|
||||||
|
};
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
import { buildRegFn, buildCachedRegFn } from './buildRegFn';
|
||||||
|
|
||||||
|
export const [getErrorHook, setErrorHook] = buildRegFn<(err: any) => boolean>(
|
||||||
|
'requestErrorHook',
|
||||||
|
() => true
|
||||||
|
);
|
||||||
|
|
||||||
|
export const [tokenGetter, setTokenGetter] =
|
||||||
|
buildCachedRegFn<() => Promise<string>>('requestTokenGetter');
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
import { request } from '../api/request';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 邮箱登录
|
||||||
|
* @param email 邮箱
|
||||||
|
* @param password 密码
|
||||||
|
*/
|
||||||
|
export async function loginWithEmail(email: string, password: string) {
|
||||||
|
const data = await request.post('/api/user/login', {
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
});
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
@ -1,4 +1,9 @@
|
|||||||
import { buildStorage, setStorage } from 'pawchat-shared';
|
import { buildStorage, setStorage, setTokenGetter } from 'pawchat-shared';
|
||||||
|
import { getUserJWT } from './utils/jwt-helper';
|
||||||
|
|
||||||
const webStorage = buildStorage(window.localStorage);
|
const webStorage = buildStorage(window.localStorage);
|
||||||
setStorage(() => webStorage);
|
setStorage(() => webStorage);
|
||||||
|
|
||||||
|
setTokenGetter(async () => {
|
||||||
|
return await getUserJWT();
|
||||||
|
});
|
||||||
|
|||||||
@ -0,0 +1,69 @@
|
|||||||
|
import _isObject from 'lodash/isObject';
|
||||||
|
import _get from 'lodash/get';
|
||||||
|
import _isNull from 'lodash/isNull';
|
||||||
|
import _isNil from 'lodash/isNil';
|
||||||
|
import jwtDecode from 'jwt-decode';
|
||||||
|
import { getStorage } from 'pawchat-shared';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取完整jwt字符串的载荷信息(尝试解析json)
|
||||||
|
* @param jwt 完整的jwt字符串
|
||||||
|
*/
|
||||||
|
export function getJWTPayload<T>(jwt: string): Partial<T> {
|
||||||
|
try {
|
||||||
|
const decoded = jwtDecode<T>(jwt);
|
||||||
|
return decoded;
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`getJWTInfo Error: [jwt: ${jwt}]`, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// JWT的内存缓存
|
||||||
|
let _userJWT: string | null = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置用户登录标识
|
||||||
|
*/
|
||||||
|
export async function setUserJWT(jwt: string): Promise<void> {
|
||||||
|
_userJWT = jwt; // 更新内存中的缓存
|
||||||
|
|
||||||
|
await getStorage().set('jsonwebtoken', jwt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户登录标识
|
||||||
|
*/
|
||||||
|
export async function getUserJWT(): Promise<string> {
|
||||||
|
if (_isNull(_userJWT)) {
|
||||||
|
const jwt = await getStorage().get('jsonwebtoken');
|
||||||
|
_userJWT = jwt; // 将其缓存到内存中
|
||||||
|
|
||||||
|
return jwt;
|
||||||
|
}
|
||||||
|
return _userJWT;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface JWTUserInfoData {
|
||||||
|
name?: string;
|
||||||
|
uuid?: string;
|
||||||
|
avatar?: string;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取token中的明文信息
|
||||||
|
* 明确需要返回一个对象
|
||||||
|
*/
|
||||||
|
export async function getJWTUserInfo(): Promise<JWTUserInfoData> {
|
||||||
|
try {
|
||||||
|
const token = await getUserJWT();
|
||||||
|
const info = getJWTPayload(token);
|
||||||
|
if (_isObject(info)) {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('getJWTInfo Error:', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue