Fix registration error responses
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 3m18s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 3m18s
This commit is contained in:
parent
ad22999fdb
commit
29867f91c1
@ -238247,7 +238247,7 @@ function validateFields(shape, source = "body") {
|
||||
if (!parseResult.success) {
|
||||
const errors = parseResult.error.issues.map((issue3) => `\u5B57\u6BB5 ${issue3.path.join(".")} ${issue3.message}`);
|
||||
console.error(errors);
|
||||
return res.status(400).json({ message: "\u53C2\u6570\u9519\u8BEF", errors });
|
||||
return res.status(400).json(error50("\u53C2\u6570\u9519\u8BEF", errors));
|
||||
}
|
||||
next();
|
||||
};
|
||||
@ -238256,6 +238256,7 @@ var init_middleware = __esm({
|
||||
"src/middleware/middleware.ts"() {
|
||||
"use strict";
|
||||
init_zod();
|
||||
init_responseFormat();
|
||||
init_locales2();
|
||||
external_exports.config(zh_CN_default());
|
||||
}
|
||||
@ -240227,6 +240228,11 @@ var init_me = __esm({
|
||||
});
|
||||
|
||||
// src/lib/smsCode.ts
|
||||
function createSmsCodeError(message) {
|
||||
const error73 = new Error(message);
|
||||
error73.status = 400;
|
||||
return error73;
|
||||
}
|
||||
function createNumericCode() {
|
||||
return String(Math.floor(1e5 + Math.random() * 9e5));
|
||||
}
|
||||
@ -240234,7 +240240,7 @@ async function assertCanSendSmsCode(phone, purpose) {
|
||||
const latest = await utils_default.db("o_smsCode").where({ phone, purpose, used: 0 }).orderBy("createTime", "desc").first();
|
||||
if (latest?.sentAt && Date.now() - latest.sentAt < RESEND_INTERVAL_MS) {
|
||||
const waitSeconds = Math.ceil((RESEND_INTERVAL_MS - (Date.now() - latest.sentAt)) / 1e3);
|
||||
throw new Error(`\u9A8C\u8BC1\u7801\u53D1\u9001\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7 ${waitSeconds} \u79D2\u540E\u518D\u8BD5`);
|
||||
throw createSmsCodeError(`\u9A8C\u8BC1\u7801\u53D1\u9001\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7 ${waitSeconds} \u79D2\u540E\u518D\u8BD5`);
|
||||
}
|
||||
}
|
||||
async function saveSmsCode(phone, purpose, code) {
|
||||
@ -240252,12 +240258,12 @@ async function saveSmsCode(phone, purpose, code) {
|
||||
}
|
||||
async function verifySmsCode(phone, purpose, code) {
|
||||
const record3 = await utils_default.db("o_smsCode").where({ phone, purpose, used: 0 }).orderBy("createTime", "desc").first();
|
||||
if (!record3) throw new Error("\u9A8C\u8BC1\u7801\u4E0D\u5B58\u5728\u6216\u5DF2\u5931\u6548");
|
||||
if ((record3.attempts ?? 0) >= MAX_ATTEMPTS) throw new Error("\u9A8C\u8BC1\u7801\u5C1D\u8BD5\u6B21\u6570\u8FC7\u591A\uFF0C\u8BF7\u91CD\u65B0\u83B7\u53D6");
|
||||
if ((record3.expiresAt ?? 0) < Date.now()) throw new Error("\u9A8C\u8BC1\u7801\u5DF2\u8FC7\u671F");
|
||||
if (!record3) throw createSmsCodeError("\u9A8C\u8BC1\u7801\u4E0D\u5B58\u5728\u6216\u5DF2\u5931\u6548");
|
||||
if ((record3.attempts ?? 0) >= MAX_ATTEMPTS) throw createSmsCodeError("\u9A8C\u8BC1\u7801\u5C1D\u8BD5\u6B21\u6570\u8FC7\u591A\uFF0C\u8BF7\u91CD\u65B0\u83B7\u53D6");
|
||||
if ((record3.expiresAt ?? 0) < Date.now()) throw createSmsCodeError("\u9A8C\u8BC1\u7801\u5DF2\u8FC7\u671F");
|
||||
await utils_default.db("o_smsCode").where("id", record3.id).update({ attempts: (record3.attempts ?? 0) + 1 });
|
||||
const matched = await verifyPassword(code, record3.codeHash);
|
||||
if (!matched) throw new Error("\u9A8C\u8BC1\u7801\u9519\u8BEF");
|
||||
if (!matched) throw createSmsCodeError("\u9A8C\u8BC1\u7801\u9519\u8BEF");
|
||||
await utils_default.db("o_smsCode").where("id", record3.id).update({ used: 1 });
|
||||
}
|
||||
var EXPIRES_IN_MS, RESEND_INTERVAL_MS, MAX_ATTEMPTS;
|
||||
@ -259834,6 +259840,7 @@ async function requestHasProjectAccess(req, userId) {
|
||||
|
||||
// src/app.ts
|
||||
init_requestContext();
|
||||
init_responseFormat();
|
||||
var app = (0, import_express173.default)();
|
||||
var server = import_node_http.default.createServer(app);
|
||||
async function checkPermissions() {
|
||||
@ -259927,11 +259934,15 @@ async function startServe(randomPort = false) {
|
||||
app.use((_, res, next) => {
|
||||
return res.status(404).send({ message: "API 404 Not Found" });
|
||||
});
|
||||
app.use((err, _, res, __) => {
|
||||
res.locals.message = err.message;
|
||||
app.use((err, _, res, next) => {
|
||||
if (res.headersSent) return next(err);
|
||||
const normalizedError = utils_default.error(err);
|
||||
const status = Number(err?.status || err?.statusCode || normalizedError.status || 500);
|
||||
const message = normalizedError.message || "\u8BF7\u6C42\u5931\u8D25";
|
||||
res.locals.message = message;
|
||||
res.locals.error = err;
|
||||
console.error(err);
|
||||
res.status(err.status || 500).send(err);
|
||||
res.status(Number.isFinite(status) ? status : 500).send(error50(message));
|
||||
});
|
||||
const port = randomPort ? 0 : 10588;
|
||||
return await new Promise((resolve3) => {
|
||||
|
||||
13
src/app.ts
13
src/app.ts
@ -16,6 +16,7 @@ import { isEletron } from "@/utils/getPath";
|
||||
import { normalizeBearerToken, verifyAuthToken } from "@/lib/auth";
|
||||
import { requestHasProjectAccess } from "@/lib/workspaceAccess";
|
||||
import { runWithRequestContext } from "@/lib/requestContext";
|
||||
import { error as formatError } from "@/lib/responseFormat";
|
||||
|
||||
const app = express();
|
||||
const server = http.createServer(app);
|
||||
@ -139,11 +140,17 @@ export default async function startServe(randomPort: Boolean = false) {
|
||||
});
|
||||
|
||||
// 错误处理
|
||||
app.use((err: any, _: Request, res: Response, __: NextFunction) => {
|
||||
res.locals.message = err.message;
|
||||
app.use((err: any, _: Request, res: Response, next: NextFunction) => {
|
||||
if (res.headersSent) return next(err);
|
||||
|
||||
const normalizedError = u.error(err);
|
||||
const status = Number(err?.status || err?.statusCode || normalizedError.status || 500);
|
||||
const message = normalizedError.message || "请求失败";
|
||||
|
||||
res.locals.message = message;
|
||||
res.locals.error = err;
|
||||
console.error(err);
|
||||
res.status(err.status || 500).send(err);
|
||||
res.status(Number.isFinite(status) ? status : 500).send(formatError(message));
|
||||
});
|
||||
|
||||
const port = randomPort ? 0 : 10588;
|
||||
|
||||
@ -7,6 +7,12 @@ const EXPIRES_IN_MS = 5 * 60 * 1000;
|
||||
const RESEND_INTERVAL_MS = 60 * 1000;
|
||||
const MAX_ATTEMPTS = 5;
|
||||
|
||||
function createSmsCodeError(message: string) {
|
||||
const error = new Error(message) as Error & { status: number };
|
||||
error.status = 400;
|
||||
return error;
|
||||
}
|
||||
|
||||
export function createNumericCode() {
|
||||
return String(Math.floor(100000 + Math.random() * 900000));
|
||||
}
|
||||
@ -15,7 +21,7 @@ export async function assertCanSendSmsCode(phone: string, purpose: SmsPurpose) {
|
||||
const latest = await u.db("o_smsCode").where({ phone, purpose, used: 0 }).orderBy("createTime", "desc").first();
|
||||
if (latest?.sentAt && Date.now() - latest.sentAt < RESEND_INTERVAL_MS) {
|
||||
const waitSeconds = Math.ceil((RESEND_INTERVAL_MS - (Date.now() - latest.sentAt)) / 1000);
|
||||
throw new Error(`验证码发送过于频繁,请 ${waitSeconds} 秒后再试`);
|
||||
throw createSmsCodeError(`验证码发送过于频繁,请 ${waitSeconds} 秒后再试`);
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,13 +41,13 @@ export async function saveSmsCode(phone: string, purpose: SmsPurpose, code: stri
|
||||
|
||||
export async function verifySmsCode(phone: string, purpose: SmsPurpose, code: string) {
|
||||
const record = await u.db("o_smsCode").where({ phone, purpose, used: 0 }).orderBy("createTime", "desc").first();
|
||||
if (!record) throw new Error("验证码不存在或已失效");
|
||||
if ((record.attempts ?? 0) >= MAX_ATTEMPTS) throw new Error("验证码尝试次数过多,请重新获取");
|
||||
if ((record.expiresAt ?? 0) < Date.now()) throw new Error("验证码已过期");
|
||||
if (!record) throw createSmsCodeError("验证码不存在或已失效");
|
||||
if ((record.attempts ?? 0) >= MAX_ATTEMPTS) throw createSmsCodeError("验证码尝试次数过多,请重新获取");
|
||||
if ((record.expiresAt ?? 0) < Date.now()) throw createSmsCodeError("验证码已过期");
|
||||
|
||||
await u.db("o_smsCode").where("id", record.id).update({ attempts: (record.attempts ?? 0) + 1 });
|
||||
const matched = await verifyPassword(code, record.codeHash);
|
||||
if (!matched) throw new Error("验证码错误");
|
||||
if (!matched) throw createSmsCodeError("验证码错误");
|
||||
|
||||
await u.db("o_smsCode").where("id", record.id).update({ used: 1 });
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import { z, ZodTypeAny } from "zod";
|
||||
import { error } from "@/lib/responseFormat";
|
||||
|
||||
import { zhCN } from "zod/locales";
|
||||
|
||||
@ -17,7 +18,7 @@ export function validateFields(
|
||||
if (!parseResult.success) {
|
||||
const errors = parseResult.error.issues.map((issue) => `字段 ${issue.path.join(".")} ${issue.message}`);
|
||||
console.error(errors);
|
||||
return res.status(400).json({ message: "参数错误", errors });
|
||||
return res.status(400).json(error("参数错误", errors));
|
||||
}
|
||||
next();
|
||||
};
|
||||
|
||||
@ -7,6 +7,35 @@ import { normalizeApiBaseUrl } from "@/utils/apiBaseUrl";
|
||||
|
||||
const instance = axios.create();
|
||||
|
||||
function isApiResponse(payload: any) {
|
||||
return payload && typeof payload === "object" && typeof payload.code === "number" && "message" in payload && "data" in payload;
|
||||
}
|
||||
|
||||
function getErrorMessage(error: any) {
|
||||
const payload = error?.response?.data ?? error;
|
||||
if (payload?.message) return payload.message;
|
||||
if (payload?.error?.message) return payload.error.message;
|
||||
if (typeof payload?.error === "string") return payload.error;
|
||||
if (Array.isArray(payload?.errors) && payload.errors.length) return payload.errors.join(";");
|
||||
if (error?.message) return error.message;
|
||||
return "请求失败,请稍后重试";
|
||||
}
|
||||
|
||||
function createRequestError(error: any) {
|
||||
const payload = error?.response?.data ?? error;
|
||||
const requestError = new Error(getErrorMessage(error)) as Error & {
|
||||
code?: string | number;
|
||||
data?: unknown;
|
||||
status?: number;
|
||||
response?: unknown;
|
||||
};
|
||||
requestError.code = payload?.code ?? error?.code;
|
||||
requestError.data = payload?.data ?? payload;
|
||||
requestError.status = error?.response?.status;
|
||||
requestError.response = error?.response;
|
||||
return requestError;
|
||||
}
|
||||
|
||||
instance.interceptors.request.use(function (config) {
|
||||
const { baseUrl, otherSetting } = storeToRefs(settingStore());
|
||||
const resolvedBaseUrl = normalizeApiBaseUrl(baseUrl.value);
|
||||
@ -24,6 +53,9 @@ instance.interceptors.request.use(function (config) {
|
||||
|
||||
instance.interceptors.response.use(
|
||||
function (response) {
|
||||
if (isApiResponse(response.data) && response.data.code !== 200) {
|
||||
return Promise.reject(createRequestError(response.data));
|
||||
}
|
||||
return response.data;
|
||||
},
|
||||
function (error) {
|
||||
@ -33,7 +65,7 @@ instance.interceptors.response.use(
|
||||
router.push("/login");
|
||||
MessagePlugin.error(window.$t("common.sessionExpired"));
|
||||
}
|
||||
return Promise.reject(error?.response?.data ?? error);
|
||||
return Promise.reject(createRequestError(error));
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user