From 8d3ad943bef59dfff327fa23b6031e8e98207de1 Mon Sep 17 00:00:00 2001 From: archer <545436317@qq.com> Date: Sat, 5 Aug 2023 12:56:37 +0800 Subject: [PATCH] perf: send code --- client/.gitignore | 2 +- client/src/pages/api/system/getInitData.ts | 4 +- client/src/pages/api/user/account/register.ts | 16 +-- .../api/user/account/updatePasswordByCode.ts | 7 +- client/src/pages/api/user/sendAuthCode.ts | 34 +---- client/src/service/api/plugins.d.ts | 11 ++ client/src/service/api/plugins.ts | 5 + client/src/service/api/request.ts | 129 ++++++++++++++++++ client/src/service/models/authCode.ts | 26 ---- client/src/service/mongo.ts | 6 - client/src/types/index.d.ts | 16 ++- 11 files changed, 167 insertions(+), 89 deletions(-) create mode 100644 client/src/service/api/plugins.d.ts create mode 100644 client/src/service/api/plugins.ts create mode 100644 client/src/service/api/request.ts delete mode 100644 client/src/service/models/authCode.ts diff --git a/client/.gitignore b/client/.gitignore index 51d4b9a6f..4b3390ce7 100644 --- a/client/.gitignore +++ b/client/.gitignore @@ -29,4 +29,4 @@ platform.json testApi/ local/ .husky/ -data/*.local \ No newline at end of file +data/*.local.* \ No newline at end of file diff --git a/client/src/pages/api/system/getInitData.ts b/client/src/pages/api/system/getInitData.ts index 839ce6e43..71f2049d9 100644 --- a/client/src/pages/api/system/getInitData.ts +++ b/client/src/pages/api/system/getInitData.ts @@ -88,7 +88,7 @@ const defaultVectorModels = [ export async function getInitConfig() { try { const filename = - process.env.NODE_ENV === 'development' ? 'data/config.json.local' : '/app/data/config.json'; + process.env.NODE_ENV === 'development' ? 'data/config.local.json' : '/app/data/config.json'; const res = JSON.parse(readFileSync(filename, 'utf-8')); console.log(res); @@ -97,6 +97,7 @@ export async function getInitConfig() { global.chatModels = res.ChatModels || defaultChatModels; global.qaModels = res.QAModels || defaultQAModels; global.vectorModels = res.VectorModels || defaultVectorModels; + global.systemPlugins = res.plugins || {}; } catch (error) { setDefaultData(); console.log('get init config error, set default', error); @@ -109,4 +110,5 @@ export function setDefaultData() { global.chatModels = defaultChatModels; global.qaModels = defaultQAModels; global.vectorModels = defaultVectorModels; + global.systemPlugins = {}; } diff --git a/client/src/pages/api/user/account/register.ts b/client/src/pages/api/user/account/register.ts index 9e44936bb..d986cc95e 100644 --- a/client/src/pages/api/user/account/register.ts +++ b/client/src/pages/api/user/account/register.ts @@ -2,10 +2,10 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { jsonRes } from '@/service/response'; import { User } from '@/service/models/user'; -import { AuthCode } from '@/service/models/authCode'; import { connectToDatabase } from '@/service/mongo'; import { generateToken, setCookie } from '@/service/utils/tools'; import { UserAuthTypeEnum } from '@/constants/common'; +import { authCode } from '@/service/api/plugins'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { @@ -18,17 +18,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< await connectToDatabase(); // 验证码校验 - const authCode = await AuthCode.findOne({ + await authCode({ username, - code, type: UserAuthTypeEnum.register, - expiredTime: { $gte: Date.now() } + code }); - if (!authCode) { - throw new Error('验证码错误'); - } - // 重名校验 const authRepeat = await User.findOne({ username @@ -51,11 +46,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< throw new Error('获取用户信息异常'); } - // 删除验证码记录 - await AuthCode.deleteMany({ - username - }); - const token = generateToken(user._id); setCookie(res, token); diff --git a/client/src/pages/api/user/account/updatePasswordByCode.ts b/client/src/pages/api/user/account/updatePasswordByCode.ts index e4f038509..c489d5167 100644 --- a/client/src/pages/api/user/account/updatePasswordByCode.ts +++ b/client/src/pages/api/user/account/updatePasswordByCode.ts @@ -2,10 +2,10 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { jsonRes } from '@/service/response'; import { User } from '@/service/models/user'; -import { AuthCode } from '@/service/models/authCode'; import { connectToDatabase } from '@/service/mongo'; import { UserAuthTypeEnum } from '@/constants/common'; import { generateToken, setCookie } from '@/service/utils/tools'; +import { authCode } from '@/service/api/plugins'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { @@ -18,11 +18,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< await connectToDatabase(); // 验证码校验 - const authCode = await AuthCode.findOne({ + await authCode({ username, code, - type: UserAuthTypeEnum.findPassword, - expiredTime: { $gte: Date.now() } + type: UserAuthTypeEnum.findPassword }); if (!authCode) { diff --git a/client/src/pages/api/user/sendAuthCode.ts b/client/src/pages/api/user/sendAuthCode.ts index e6a69b6f9..b04321c20 100644 --- a/client/src/pages/api/user/sendAuthCode.ts +++ b/client/src/pages/api/user/sendAuthCode.ts @@ -1,13 +1,9 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { jsonRes } from '@/service/response'; -import { AuthCode } from '@/service/models/authCode'; -import { connectToDatabase } from '@/service/mongo'; -import { sendPhoneCode, sendEmailCode } from '@/service/utils/sendNote'; import { UserAuthTypeEnum } from '@/constants/common'; -import { customAlphabet } from 'nanoid'; -const nanoid = customAlphabet('123456789', 6); import { authGoogleToken } from '@/utils/plugin/google'; import requestIp from 'request-ip'; +import { sendCode } from '@/service/api/plugins'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { @@ -29,40 +25,16 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) remoteip: requestIp.getClientIp(req) || undefined })); - await connectToDatabase(); - // register switch if (type === UserAuthTypeEnum.register && !global.feConfigs?.show_register) { throw new Error('Register is closed'); } - const code = nanoid(); - - // 判断 1 分钟内是否有重复数据 - const authCode = await AuthCode.findOne({ + await sendCode({ username, - type, - expiredTime: { $gte: Date.now() + 4 * 60 * 1000 } // 如果有一个记录的过期时间,大于当前+4分钟,说明距离上次发送还没到1分钟。(因为默认创建时,过期时间是未来5分钟) + type }); - if (authCode) { - throw new Error('请勿频繁获取验证码'); - } - - // 创建 auth 记录 - await AuthCode.create({ - username, - type, - code - }); - - if (username.includes('@')) { - await sendEmailCode(username, code, type); - } else { - // 发送验证码 - await sendPhoneCode(username, code); - } - jsonRes(res, { message: '发送验证码成功' }); diff --git a/client/src/service/api/plugins.d.ts b/client/src/service/api/plugins.d.ts new file mode 100644 index 000000000..39b51e0c9 --- /dev/null +++ b/client/src/service/api/plugins.d.ts @@ -0,0 +1,11 @@ +import { UserAuthTypeEnum } from '../../constants/common'; + +export type SendCodeBody = { + username: string; + type: `${UserAuthTypeEnum}`; +}; +export type AuthCodeBody = { + username: string; + type: `${UserAuthTypeEnum}`; + code: string; +}; diff --git a/client/src/service/api/plugins.ts b/client/src/service/api/plugins.ts new file mode 100644 index 000000000..afb5dd325 --- /dev/null +++ b/client/src/service/api/plugins.ts @@ -0,0 +1,5 @@ +import { POST } from './request'; +import type { SendCodeBody, AuthCodeBody } from './plugins.d'; + +export const sendCode = (data: SendCodeBody) => POST(global.systemPlugins.authCode?.sendUrl, data); +export const authCode = (data: AuthCodeBody) => POST(global.systemPlugins.authCode?.authUrl, data); diff --git a/client/src/service/api/request.ts b/client/src/service/api/request.ts new file mode 100644 index 000000000..a7e5a2b0b --- /dev/null +++ b/client/src/service/api/request.ts @@ -0,0 +1,129 @@ +import axios, { Method, InternalAxiosRequestConfig, AxiosResponse } from 'axios'; +import { clearToken, getToken } from '@/utils/user'; +import { TOKEN_ERROR_CODE } from '@/service/errorCode'; + +interface ConfigType { + headers?: { [key: string]: string }; + hold?: boolean; + timeout?: number; +} +interface ResponseDataType { + code: number; + message: string; + data: any; +} + +/** + * 请求开始 + */ +function requestStart(config: InternalAxiosRequestConfig): InternalAxiosRequestConfig { + if (config.headers) { + // config.headers.token = getToken(); + } + + return config; +} + +/** + * 请求成功,检查请求头 + */ +function responseSuccess(response: AxiosResponse) { + return response; +} +/** + * 响应数据检查 + */ +function checkRes(data: ResponseDataType) { + if (data === undefined) { + console.log('error->', data, 'data is empty'); + return Promise.reject('服务器异常'); + } else if (data.code < 200 || data.code >= 400) { + return Promise.reject(data); + } + return data.data; +} + +/** + * 响应错误 + */ +function responseError(err: any) { + if (!err) { + return Promise.reject({ message: '未知错误' }); + } + if (typeof err === 'string') { + return Promise.reject({ message: err }); + } + // 有报错响应 + if (err?.code in TOKEN_ERROR_CODE) { + clearToken(); + window.location.replace( + `/login?lastRoute=${encodeURIComponent(location.pathname + location.search)}` + ); + return Promise.reject({ message: 'token过期,重新登录' }); + } + if (err?.response?.data) { + return Promise.reject(err?.response?.data); + } + return Promise.reject(err); +} + +/* 创建请求实例 */ +const instance = axios.create({ + timeout: 60000, // 超时时间 + headers: { + 'content-type': 'application/json' + } +}); + +/* 请求拦截 */ +instance.interceptors.request.use(requestStart, (err) => Promise.reject(err)); +/* 响应拦截 */ +instance.interceptors.response.use(responseSuccess, (err) => Promise.reject(err)); + +function request(url: string, data: any, config: ConfigType, method: Method): any { + /* 去空 */ + for (const key in data) { + if (data[key] === null || data[key] === undefined) { + delete data[key]; + } + } + + return instance + .request({ + baseURL: '/api', + url, + method, + data: ['POST', 'PUT'].includes(method) ? data : null, + params: !['POST', 'PUT'].includes(method) ? data : null, + ...config // 用户自定义配置,可以覆盖前面的配置 + }) + .then((res) => checkRes(res.data)) + .catch((err) => responseError(err)); +} + +/** + * api请求方式 + * @param {String} url + * @param {Any} params + * @param {Object} config + * @returns + */ +export function GET(url?: string, params = {}, config: ConfigType = {}): Promise { + if (!url) return Promise.reject('no url'); + return request(url, params, config, 'GET'); +} + +export function POST(url?: string, data = {}, config: ConfigType = {}): Promise { + if (!url) return Promise.reject('no url'); + return request(url, data, config, 'POST'); +} + +export function PUT(url?: string, data = {}, config: ConfigType = {}): Promise { + if (!url) return Promise.reject('no url'); + return request(url, data, config, 'PUT'); +} + +export function DELETE(url?: string, data = {}, config: ConfigType = {}): Promise { + if (!url) return Promise.reject('no url'); + return request(url, data, config, 'DELETE'); +} diff --git a/client/src/service/models/authCode.ts b/client/src/service/models/authCode.ts deleted file mode 100644 index 3b1a3c423..000000000 --- a/client/src/service/models/authCode.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Schema, model, models, Model } from 'mongoose'; -import { AuthCodeSchema as AuthCodeType } from '@/types/mongoSchema'; - -const AuthCodeSchema = new Schema({ - username: { - type: String, - required: true - }, - code: { - type: String, - required: true, - length: 6 - }, - type: { - type: String, - enum: ['register', 'findPassword'], - required: true - }, - expiredTime: { - type: Number, - default: () => Date.now() + 5 * 60 * 1000 - } -}); - -export const AuthCode: Model = - models['auth_code'] || model('auth_code', AuthCodeSchema); diff --git a/client/src/service/mongo.ts b/client/src/service/mongo.ts index 35936173b..37995def3 100644 --- a/client/src/service/mongo.ts +++ b/client/src/service/mongo.ts @@ -19,11 +19,6 @@ export async function connectToDatabase(): Promise { // init global data global.qaQueueLen = 0; global.vectorQueueLen = 0; - global.systemEnv = { - vectorMaxProcess: 10, - qaMaxProcess: 10, - pgIvfflatProbe: 10 - }; global.sendInformQueue = []; global.sendInformQueueLen = 0; // proxy obj @@ -116,7 +111,6 @@ async function initPg() { } } -export * from './models/authCode'; export * from './models/chat'; export * from './models/app'; export * from './models/user'; diff --git a/client/src/types/index.d.ts b/client/src/types/index.d.ts index c14bb13cd..751951475 100644 --- a/client/src/types/index.d.ts +++ b/client/src/types/index.d.ts @@ -31,13 +31,15 @@ export type SystemEnvType = { qaMaxProcess: number; pgIvfflatProbe: number; }; -type PluginItemType = { - url: string; - auth: string; -}; + export type PluginType = { - authCode?: PluginItemType; - moderationsCheck?: PluginItemType; + authCode?: { + sendUrl: string; + authUrl: string; + }; + moderationsCheck?: { + url: string; + }; }; declare global { @@ -52,7 +54,7 @@ declare global { var feConfigs: FeConfigsType; var systemEnv: SystemEnvType; - var; + var systemPlugins: PluginType; var chatModels: ChatModelItemType[]; var qaModels: QAModelItemType[]; var vectorModels: VectorModelItemType[];