refactor: login request

pull/13/head
moonrailgun 4 years ago
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',
};

@ -20,3 +20,7 @@ export { useMountedState } from './hooks/useMountedState';
// manager
export { getStorage, setStorage, useStorage } from './manager/storage';
export { setTokenGetter } from './manager/request';
// model
export { loginWithEmail } from './model/user';

@ -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;
}

@ -7,6 +7,7 @@
"license": "GPLv3",
"private": true,
"dependencies": {
"axios": "^0.21.1",
"formik": "^2.2.9",
"lodash": "^4.17.21",
"react-native-storage": "npm:@trpgengine/react-native-storage@^1.0.1",

@ -16,6 +16,7 @@
"@loadable/component": "^5.15.0",
"antd": "^4.16.6",
"clsx": "^1.1.1",
"jwt-decode": "^3.1.2",
"p-min-delay": "^4.0.0",
"pawchat-shared": "*",
"react": "^17.0.2",

@ -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);
setStorage(() => webStorage);
setTokenGetter(async () => {
return await getUserJWT();
});

@ -1,15 +1,15 @@
import { Icon } from '@iconify/react';
import { Divider } from 'antd';
import { useAsyncFn } from 'pawchat-shared';
import { loginWithEmail, useAsyncFn } from 'pawchat-shared';
import React, { useState } from 'react';
import { Spinner } from '../../components/Spinner';
import { string } from 'yup';
/**
* TODO:
*
*/
const OAuthLoginView: React.FC = React.memo(() => {
// TODO
return (
<>
<Divider></Divider>
@ -42,11 +42,7 @@ export const LoginView: React.FC = React.memo(() => {
.required('密码不能为空')
.validate(password);
await new Promise((resolve) => {
setTimeout(() => {
resolve('');
}, 2000);
});
await loginWithEmail(email, password);
}, [email, password]);
return (

@ -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 {};
}

@ -1452,6 +1452,13 @@ autoprefixer@^10.2.6:
normalize-range "^0.1.2"
postcss-value-parser "^4.1.0"
axios@^0.21.1:
version "0.21.1"
resolved "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
dependencies:
follow-redirects "^1.10.0"
babel-jest@^27.0.6:
version "27.0.6"
resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-27.0.6.tgz#e99c6e0577da2655118e3608b68761a5a69bd0d8"
@ -2947,7 +2954,7 @@ find-up@^4.0.0, find-up@^4.1.0:
locate-path "^5.0.0"
path-exists "^4.0.0"
follow-redirects@^1.0.0:
follow-redirects@^1.0.0, follow-redirects@^1.10.0:
version "1.14.1"
resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz#d9114ded0a1cfdd334e164e6662ad02bfd91ff43"
integrity sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==
@ -4356,6 +4363,11 @@ jsonfile@^6.0.1:
optionalDependencies:
graceful-fs "^4.1.6"
jwt-decode@^3.1.2:
version "3.1.2"
resolved "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz#3fb319f3675a2df0c2895c8f5e9fa4b67b04ed59"
integrity sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==
killable@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892"

Loading…
Cancel
Save