Nginx 返回 405 Method Not Allowed 的场景比想象中更常见。很多请求能够正常到达 Nginx,甚至 location 规则也能匹配到,但最终却被拒绝,原因在于 Nginx 自身的模块并不支持该请求方法。最常见的例子是向一个纯静态资源发起 PUT、DELETE 或 PATCH 请求,或者在一个被错误配置的 location 中访问动态接口。搞清楚 Nginx 在哪个环节判定方法不允许,是解决问题的基础。

需要明确的是,Nginx 返回的 405 与后端应用返回的 405 并不总是同一回事。如果请求经过 Nginx 直接由静态文件模块处理,那么方法限制来自 Nginx 内部;如果请求被代理到后端,405 可能来自后端框架或服务。本文先分析 Nginx 自身的触发逻辑,再给出针对不同场景的配置方法。
Nginx 405错误的触发机制
Nginx 的静态文件处理模块 ngx_http_static_module 在接收到请求后,会先检查请求方法是否在允许范围内。从源码逻辑来看,它只接受 GET、HEAD 和 POST 三种方法。如果方法不匹配,模块会直接返回 NGX_HTTP_NOT_ALLOWED,对应 HTTP 状态码就是 405,并附带一个响应头 Allow: GET, HEAD, POST。这意味着即使文件真实存在,PUT、DELETE、PATCH 等请求也无法被静态模块处理。
另一个容易混淆的点是 limit_except 指令。它的作用不是改变模块支持的方法,而是在访问控制层面进行限制。例如在 location 中配置 limit_except GET POST { deny all; } 后,除了 GET 和 POST 以外的所有方法都会被拒绝,但拒绝时返回的默认是 403 Forbidden 而不是 405。因为 limit_except 本质上做的是权限控制,而非方法支持判断。如果 location 本身是由静态模块处理,即便 limit_except 放行了 PUT,静态模块依然会返回 405,因为底层根本不支持 PUT。
还有一种情况是请求被代理到后端,但后端因为业务逻辑返回了 405。此时 Nginx 只是一个转发者,返回的 405 与 Nginx 自身无关。排查时可以观察响应头中是否包含 Nginx 的版本信息,或者直接查看后端日志。通常可以通过 curl -X PUT -I http://ipipp.com/resource 这样的命令来复现问题,并判断响应体是否来自后端应用。
使用 limit_except 精细控制 HTTP 方法
要允许指定的 HTTP 方法通过 Nginx,首先需要确保请求不会被静态模块直接处理。对于动态接口或需要代理的路径,可以将 location 配置为 proxy_pass,此时 Nginx 会原样转发方法,不会再因为方法不被支持而返回 405。在此基础上,再通过 limit_except 做方法白名单,可以精细控制哪些方法可以访问该 location。
以下配置允许 GET、POST、PUT、DELETE 和 OPTIONS 方法访问 /api/ 下的接口,其他方法如 PATCH、TRACE 等会被拒绝,并且返回 403 状态码。如果希望返回 405,可以在 limit_except 块内使用 return 405; 替换 deny all;。
location /api/ {
limit_except GET POST PUT DELETE OPTIONS {
deny all;
}
proxy_pass http://backend;
}
需要注意,limit_except 的块内指令是针对“除列表之外的方法”生效的。例如上面的配置中,deny all 只对 PATCH、TRACE 等未被列出的方法生效,因此实际效果是 GET、POST、PUT、DELETE、OPTIONS 可以正常通过,其他方法被拒绝。如果忘记加入 OPTIONS,浏览器跨域预检请求会失败,因为预检请求使用 OPTIONS 方法,会直接命中 deny all 返回 403,导致前端控制台出现 CORS 错误。
对于纯静态文件场景,如果确实需要支持 PUT、DELETE 等方法,单纯用 limit_except 是无效的,因为静态模块依然不处理这些方法。此时必须改变处理逻辑,例如将对应路径通过 error_page 接管,或者直接使用 proxy_pass 转发给一个能处理这些方法的动态服务。
用 error_page 接管 405 并保留请求方法
当静态文件请求遇到 405 时,可以通过 error_page 指令将错误处理定向到一个命名 location,从而接管原本会被拒绝的方法。一个基础配置如下:
server {
listen 80;
root /var/www/html;
location / {
error_page 405 = @method_fallback;
try_files $uri $uri/ =404;
}
location @method_fallback {
proxy_pass http://127.0.0.1:8080;
}
}
这个配置在遇到 405 时会内部重定向到 @method_fallback,再由该命名 location 将请求代理到本机 8080 端口的后端服务。但这里有一个关键问题:Nginx 的 error_page 内部重定向会创建一个新的子请求,在默认情况下,新子请求的方法会被重置为 GET,原始方法(例如 PUT)可能丢失。如果后端需要收到原始的 PUT 方法,就必须在命名 location 中显式设置代理方法。
可以通过 proxy_method 指令配合变量来保留原始方法,如下所示:
location @method_fallback {
proxy_method $request_method;
proxy_pass http://127.0.0.1:8080;
}
这样 Nginx 在转发时会使用保存在 $request_method 变量中的原始方法。但要注意,proxy_method 在某些版本中可能对变量支持有限,需要测试确认。更稳妥的做法是直接为需要支持非标准方法的路径配置 proxy_pass,而不让静态模块参与处理,这样可以完全避免 405 的产生,也无需担心方法丢失问题。
常见场景与完整配置建议
场景一:RESTful API 经过 Nginx 时返回 405。这通常是因为 API 路径没有匹配到 proxy_pass 的 location,而是落到了静态文件处理规则中,例如一个以 /api 开头的路径被 try_files 或 root 配置截获。解决方法是将所有 API 路径严格匹配到代理 location,确保静态处理只针对真实的静态资源目录。
场景二:纯静态站点需要支持 WebDAV 方法,如 PUT、DELETE、MKCOL 等。Nginx 官方提供了 ngx_http_dav_module 模块,但它默认只支持 PUT、DELETE、MKCOL、COPY、MOVE 等方法,且需要编译时启用。如果不想引入额外模块,建议将这类请求代理到专门的文件服务,而不是强行让 ngx_http_static_module 支持。
场景三:前端跨域请求触发 OPTIONS 预检失败。无论使用 limit_except 还是 error_page,都必须显式允许 OPTIONS 方法。推荐在 server 块或 API location 中统一处理 OPTIONS,例如直接返回 204 状态码:
location /api/ {
if ($request_method = OPTIONS) {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
add_header Access-Control-Allow-Headers "Authorization, Content-Type";
return 204;
}
limit_except GET POST PUT DELETE OPTIONS {
deny all;
}
proxy_pass http://backend;
}
这份配置在进入方法限制之前先处理了 OPTIONS 预检,返回 204 并附加 CORS 头,避免预检请求进入 limit_except 造成额外问题。同时保留了 limit_except 对其他方法的限制,确保只有白名单方法能够访问后端接口。
综合来看,允许指定 HTTP 方法的关键是理解 Nginx 的模块处理流程:静态模块只认 GET、HEAD、POST;limit_except 负责访问控制而不是方法支持;动态代理则根据后端能力放行方法。根据实际场景选择合适的组合方案,才能在不破坏现有配置的前提下,精准放行目标方法并避免衍生错误。
Nginx 405HTTP方法Method Not Allowed修改时间:2026-09-22 05:33:56