feat: complete CORS config-driven middleware rewrite
- cors.ts: createCorsMiddleware factory with RuntimeConfig param - Wildcard ['*'] mode: Access-Control-Allow-Origin: * (backward compatible) - Specific origins mode: reflect matching origin + Allow-Credentials - Added Access-Control-Max-Age: 86400 for preflight caching - app.ts: accept config param, use createCorsMiddleware(config) - index.ts: pass runtimeConfig to createApp - env-overrides.ts: add string[] to RuntimeConfigValue, corsOriginsEnv helper - runtime-config.ts: cors.allowedOrigins: string[] type - defaults.ts: cors.allowedOrigins: ['*'] default - .env: CORS_ALLOWED_ORIGINS=* with production example
This commit is contained in:
@@ -9,22 +9,24 @@ import tencentRouter from "./routes/tencent.js";
|
|||||||
import webhooksRouter from "./routes/webhooks.js";
|
import webhooksRouter from "./routes/webhooks.js";
|
||||||
import { buildSuccessPayload, sendRouteError } from "./utils/http.js";
|
import { buildSuccessPayload, sendRouteError } from "./utils/http.js";
|
||||||
import { accessLogMiddleware } from "./middleware/access-log.js";
|
import { accessLogMiddleware } from "./middleware/access-log.js";
|
||||||
import { corsMiddleware } from "./middleware/cors.js";
|
import { createCorsMiddleware } from "./middleware/cors.js";
|
||||||
|
import type { RuntimeConfig } from "./types/runtime-config.js";
|
||||||
import { buildHealthPayload, type StartupState } from "./startup/state.js";
|
import { buildHealthPayload, type StartupState } from "./startup/state.js";
|
||||||
|
|
||||||
type CreateAppOptions = {
|
type CreateAppOptions = {
|
||||||
startupState: StartupState;
|
startupState: StartupState;
|
||||||
isShutdownStarted: () => boolean;
|
isShutdownStarted: () => boolean;
|
||||||
|
config: RuntimeConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function createApp({
|
export function createApp({
|
||||||
startupState,
|
startupState,
|
||||||
isShutdownStarted,
|
isShutdownStarted,
|
||||||
|
config,
|
||||||
}: CreateAppOptions) {
|
}: CreateAppOptions) {
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
app.use(accessLogMiddleware);
|
app.use(accessLogMiddleware);
|
||||||
app.use(corsMiddleware);
|
app.use(createCorsMiddleware(config));
|
||||||
app.use(express.json({ limit: "2mb" }));
|
app.use(express.json({ limit: "2mb" }));
|
||||||
app.use(express.urlencoded({ extended: true }));
|
app.use(express.urlencoded({ extended: true }));
|
||||||
|
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ try {
|
|||||||
logError("[startup]", "运行时配置校验失败,服务停止启动", error);
|
logError("[startup]", "运行时配置校验失败,服务停止启动", error);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const app = createApp({
|
const app = createApp({
|
||||||
startupState,
|
startupState,
|
||||||
isShutdownStarted: () => shutdownController?.isShutdownStarted() || false,
|
isShutdownStarted: () => shutdownController?.isShutdownStarted() || false,
|
||||||
|
config: runtimeConfig,
|
||||||
});
|
});
|
||||||
|
|
||||||
const server = app.listen(port, host, () => {
|
const server = app.listen(port, host, () => {
|
||||||
|
|||||||
@@ -1,16 +1,37 @@
|
|||||||
import type { Request, Response, NextFunction } from "express";
|
import type { Request, Response, NextFunction } from "express";
|
||||||
|
import type { RuntimeConfig } from "../types/runtime-config.js";
|
||||||
|
|
||||||
export function corsMiddleware(
|
export function createCorsMiddleware(
|
||||||
|
config: RuntimeConfig
|
||||||
|
): (req: Request, res: Response, next: NextFunction) => void {
|
||||||
|
const allowedOrigins = config.cors.allowedOrigins;
|
||||||
|
const isWildcard =
|
||||||
|
allowedOrigins.length === 1 && allowedOrigins[0] === "*";
|
||||||
|
|
||||||
|
return function corsMiddleware(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
next: NextFunction
|
next: NextFunction
|
||||||
): void {
|
): void {
|
||||||
|
if (isWildcard) {
|
||||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||||
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
|
} else {
|
||||||
|
const origin = req.headers.origin;
|
||||||
|
if (origin && allowedOrigins.includes(origin)) {
|
||||||
|
res.setHeader("Access-Control-Allow-Origin", origin);
|
||||||
|
res.setHeader("Access-Control-Allow-Credentials", "true");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.setHeader(
|
||||||
|
"Access-Control-Allow-Headers",
|
||||||
|
"Content-Type, Authorization"
|
||||||
|
);
|
||||||
res.setHeader(
|
res.setHeader(
|
||||||
"Access-Control-Allow-Methods",
|
"Access-Control-Allow-Methods",
|
||||||
"GET, POST, PUT, PATCH, DELETE, OPTIONS"
|
"GET, POST, PUT, PATCH, DELETE, OPTIONS"
|
||||||
);
|
);
|
||||||
|
res.setHeader("Access-Control-Max-Age", "86400");
|
||||||
|
|
||||||
if (req.method === "OPTIONS") {
|
if (req.method === "OPTIONS") {
|
||||||
res.sendStatus(204);
|
res.sendStatus(204);
|
||||||
@@ -18,4 +39,5 @@ export function corsMiddleware(
|
|||||||
}
|
}
|
||||||
|
|
||||||
next();
|
next();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user