Files
SnowLuma/.pnpm-store/v11/files/e9/d2650ed071417a0b2706a7edbafc1a0b7f03113e7bdddaca403b9cf785e4e9be51687c0bcffd5862a0771c15fc82bfa810340640ea4f36ec2c46db55c0f713
T
TanTan 2a69b23b47
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
docs: 仓库链接指向本镜像仓库
2026-11-13 09:27:07 +08:00

84 lines
3.2 KiB
Plaintext

import "../../router.js";
import { TrieRouter } from "../../router/trie-router/router.js";
import "../../router/trie-router/index.js";
import { basePath, matchedRoutes } from "../../helper/route/index.js";
//#region src/middleware/method-not-allowed/index.ts
/**
* Method Not Allowed Middleware for Hono.
*
* Returns a `405 Method Not Allowed` response with an `Allow` header when the request path
* matches a registered route but the request method is not supported.
*
* @param {MethodNotAllowedOptions} options - The options for the middleware.
* @param {Hono} options.app - The Hono instance used by the application.
* @param {MethodNotAllowedHandler} [options.onMethodNotAllowed] - Generates the response, including its `Allow` header.
* @returns {MiddlewareHandler} The middleware handler function.
*
* @example
* ```ts
* const app = new Hono()
*
* app.use(methodNotAllowed({ app }))
*
* app.get('/hello', (c) => c.text('Hello!'))
* app.post('/hello', (c) => c.text('Posted!'))
*
* // PUT /hello -> 405 Method Not Allowed
* // Allow: GET, HEAD, POST
* ```
*
* @example
* ```ts
* app.use(
* methodNotAllowed({
* app,
* onMethodNotAllowed: (c, methods) =>
* c.json({ error: 'Method Not Allowed' }, 405, { Allow: methods.join(', ') }),
* })
* )
* ```
*/
const methodNotAllowed = (options) => {
let methodRouter;
return async function methodNotAllowed(c, next) {
const routeIndex = c.req.routeIndex;
await next();
if (c.res.status !== 404) return;
if (c.error) return;
if (!methodRouter) {
const methodsByPath = /* @__PURE__ */ new Map();
for (const route of options.app.routes) {
if (route.method === "ALL" || route.method === "HEAD") continue;
const methods = methodsByPath.get(route.path) ?? /* @__PURE__ */ new Set();
methods.add(route.method);
if (route.method === "GET") methods.add("HEAD");
methodsByPath.set(route.path, methods);
}
methodRouter = new TrieRouter();
for (const [path, methods] of methodsByPath) methodRouter.add("ALL", path, [...methods]);
}
let requestPath = c.req.path;
const currentRoute = matchedRoutes(c)[routeIndex];
const sourceRoute = options.app.routes.find((route) => route.handler === methodNotAllowed);
if (currentRoute && sourceRoute) {
const currentBasePathParts = basePath(c, routeIndex).split("/").filter(Boolean);
const sourceBasePathLength = sourceRoute.basePath.split("/").filter(Boolean).length;
const mountBasePathParts = currentBasePathParts.slice(0, currentBasePathParts.length - sourceBasePathLength);
if (mountBasePathParts.length > 0) {
const mountBasePath = `/${mountBasePathParts.join("/")}`;
requestPath = c.req.path.slice(mountBasePath.length) || "/";
}
}
const allowedMethods = /* @__PURE__ */ new Set();
for (const [methods] of methodRouter.match("ALL", requestPath)[0]) for (const method of methods) allowedMethods.add(method);
if (allowedMethods.size === 0 || allowedMethods.has(c.req.method)) return;
c.res.headers.delete("Allow");
c.res.headers.delete("Content-Length");
const methods = [...allowedMethods];
const allow = methods.join(", ");
c.res = options.onMethodNotAllowed ? await options.onMethodNotAllowed(c, methods) : c.text("Method Not Allowed", 405, { Allow: allow });
};
};
//#endregion
export { methodNotAllowed };