后端面试:405 Method Not Allowed 为什么必须返回 Allow?
题目
你维护一个文件 API:GET /v1/files/:id 可以读取文件,客户端却向同一个资源发送 POST 或 DELETE。面试官要求你设计响应,并说明 405、404、403、OPTIONS 和 CORS 预检的区别。请给出路由判定、Allow 头、错误体、测试与上线策略。
背景与约束
- 资源路由已经匹配到具体文件,但该资源当前只开放
GET和HEAD。 - 客户端可能因为 SDK 版本不一致而误用方法,代理层也可能改写或拦截请求。
- API 需要让调用方可诊断,同时不能把未启用的方法误报为可用。
- 若资源存在性本身敏感,团队可以采用一致的 404 隐藏策略,但必须在接口契约中明确。
面试官考察点
先区分资源匹配与方法分派
先完成主机、路径、版本和资源标识的匹配,再查该资源的允许方法集合。路径不存在时返回 404;路径存在但方法不在集合中时返回 405。授权检查仍要遵循系统的安全策略:请求者无权访问可返回 403,不能把所有权限失败都伪装成 405。
405 必须带 Allow
405 表示服务器认识请求方法,但目标资源不支持它。响应必须带 Allow,列出该资源当前支持的方法,例如:
HTTP/1.1 405 Method Not Allowed
Allow: GET, HEAD, OPTIONS
Content-Type: application/problem+json
{"type":"about:blank","title":"Method Not Allowed","status":405,"detail":"Use one of the methods listed in Allow."}Allow 描述资源能力;它与 CORS 的 Access-Control-Allow-Methods 不是同一个头。后者只参与浏览器跨来源策略,不能替代 405 的方法契约。
OPTIONS 要单独建模
OPTIONS 可用于询问通信选项,浏览器 CORS 预检还会携带 Origin 与 Access-Control-Request-Method。预检是否成功取决于 CORS 响应头和认证策略;不能因为看到 OPTIONS 就把所有请求改成 405,也不能把 Allow 当成 CORS 授权清单。
回答前需要澄清的问题
- 资源是否确实存在?若不存在,按 404 处理;若安全策略隐藏存在性,需确认是否统一返回 404。
- 允许方法是否随租户、资源状态或 API 版本变化?答案会决定
Allow的生成上下文与缓存键。 - 网关是否会改写未知方法,或由谁负责生成
Allow?答案会决定排查边界和唯一数据源。
30 秒回答框架
“路径已经匹配,但请求方法不在该资源的能力集合中,所以返回 405,并在 Allow 中列出当前真正支持的方法。路径不存在才是 404,权限拒绝按策略是 403;OPTIONS 和 CORS 预检另有一套响应头。最后我会用方法矩阵、真实网关链路和灰度指标验证它。”
分步骤深入解答
把每条资源路由的允许方法定义为可审计的注册表,并让路由器在同一份注册表上完成分派与生成 Allow。对 POST /v1/files/123,若资源存在且 POST 未注册,返回 405;对不存在的 123 返回 404;对已匹配但无访问权限的请求按授权策略返回 403。HEAD 通常应与 GET 的可读能力保持一致,但仍要以框架实际行为为准。
错误体应给出稳定的状态、标题和可行动的说明,避免泄露堆栈或内部路由细节。Allow 只列实际启用的方法,灰度期间不要提前宣传尚未部署的写入能力。若采用隐藏资源存在性的安全策略,应对 404 与 405 的选择、日志字段和客户端重试行为写入契约。
高质量示范回答
“我会先让路由器确认文件资源是否存在,再从唯一的方法注册表做分派。对存在的文件收到未注册的 POST,返回 405,并把 GET, HEAD 以及实际支持的 OPTIONS 写进 Allow;不存在的文件返回 404,已匹配但无权限则按授权策略返回 403。CORS 预检使用 Access-Control-Allow-Methods,不能拿它代替 Allow。网关和应用只保留一个生成源,契约测试会逐项检查状态码和方法集合,灰度时监控 405 按方法的分布。”
常见错误
- 把“路径存在但方法不支持”写成 404,调用方无法判断是 URL 错误还是方法错误。
- 返回 405 却遗漏
Allow,客户端无法自动发现可用方法,也违背 HTTP 语义。 - 用
Access-Control-Allow-Methods代替Allow,混淆 HTTP 能力和浏览器跨域授权。 - 把鉴权失败统一改成 405,导致安全审计、监控和客户端处理失真。
- 由网关生成一套
Allow、应用生成另一套Allow,代理缓存后出现不一致。
错误表现与修正
把 405 当成通用失败码、遗漏 Allow,或把 CORS 头当成 Allow,都会让调用方无法采取下一步。修正方法是先完成资源匹配,再从同一份方法注册表生成状态码和头部,并为 404、403、405 与预检分别建测试。
生产化实现
路由与代理协作
让网关透传应用的 405 和 Allow,或明确由网关统一生成并禁止应用重复覆盖。对每个版本维护方法矩阵,记录缓存、幂等性、认证和幂等重试要求。若代理把未知方法降级为 GET,应先修正代理策略,否则应用永远看不到真实方法。
可观测性与兼容
记录请求方法、规范化路径、路由版本、响应状态和最终 Allow 集合,不记录敏感文件内容。客户端收到 405 后应停止对同一方法盲目重试,改用契约允许的方法或升级 SDK。对于旧客户端,可先在日志和文档中观察误用,再通过版本化变更逐步收紧。
验证清单
契约测试
为每个资源建立方法矩阵,至少覆盖:已注册方法成功、未注册方法返回 405、路径不存在返回 404、授权拒绝返回 403,以及 Allow 与实际路由一致。断言状态码、头部方法集合、内容类型和错误体字段。
集成与回归
通过真实 HTTP 客户端验证网关、负载均衡和应用的组合行为;单独验证 OPTIONS 与 CORS 预检,检查 Access-Control-Allow-Methods 不会代替 Allow。灰度期间对 405 比例、按方法分布和错误体解析失败率设告警。
追问及应对
什么时候可以返回 404 而非 405?
当路径确实不存在,或安全策略要求隐藏资源存在性时,可以返回 404。关键是对同一类资源保持一致,并在文档、日志和客户端策略中说明,避免同一接口在不同节点随机返回 404 或 405。
Allow 是否一定要包含 OPTIONS?
只有当该资源实际接受 OPTIONS 时才列出。框架自动处理 OPTIONS 时,应确认它的响应和应用路由契约一致;不能为了“看起来完整”添加未实现的方法。
如何处理动态能力?
若方法能力随租户、版本或资源状态变化,生成 Allow 时必须使用当前请求上下文,并让缓存键包含影响能力的维度。更稳妥的做法是减少中间层缓存 405,或显式设置合适的缓存策略。
评分标准
- 语义准确:能说明 405 的触发条件和
Allow的强制性。 - 边界清楚:能区分 404、403、OPTIONS、CORS 与资源安全隐藏策略。
- 实现可落地:路由注册表、代理协作、错误体和可观测性具体。
- 验证完整:覆盖方法矩阵、真实 HTTP 链路、灰度指标与回归。
- 风险意识:不误报方法、不泄露内部细节、不让网关与应用产生分歧。
参考资料
- MDN:405 Method Not Allowed
- MDN:Allow header
- Postman:HTTP Error 405
- JustAcademy:REST API interview questions
面试作答要点
先说“资源已匹配、方法不支持、返回 405”,再给出 Allow 的实际集合;随后区分 404、403、OPTIONS 和 CORS,最后补上方法矩阵、代理一致性与测试证据。
一句话总结
405 负责表达资源的方法不匹配,Allow 负责告诉客户端当前可用方法,两者共同构成可诊断的 HTTP 契约。