如何避免Nginx对无效HTTP请求返回多个响应
问题:如何抑制Nginx对无效HTTP请求返回的第二个400响应
有一个无效的HTTP请求示例如下:
POST / HTTP/1.1 Host: 127.0.0.1 Connection: keep-alive Accept: */* User-Agent: NonExistent Client Content-Length: 4 foo=bar
该请求的核心问题是:请求体实际长度为7字节,但Content-Length标头仅设置为4,属于格式错误的请求。
Nginx针对这个请求返回了两个响应:
HTTP/1.1 404 Not Found Date: Fri, 03 Mar 2023 20:55:02 GMT Content-Type: text/html Content-Length: 146 Connection: keep-alive Vary: Accept-Encoding X-XSS-Protection: 0 X-Content-Type-Options: nosniff <html> <head><title>404 Not Found</title></head> <body> <center><h1>404 Not Found</h1></center> <hr><center>nginx</center> </body> </html> HTTP/1.1 400 Bad Request Date: Fri, 03 Mar 2023 20:55:02 GMT Content-Type: text/html Content-Length: 150 Connection: close X-XSS-Protection: 0 X-Content-Type-Options: nosniff <html> <head><title>400 Bad Request</title></head> <body> <center><h1>400 Bad Request</h1></center> <hr><center>nginx</center> </body> </html>
第一个是预期的404响应(请求路径不存在),第二个400响应则是因为服务器继续读取了请求体的剩余部分,并将其误判为新的流水线请求行,日志记录如下:
2023/03/03 20:55:02 [info] 27273#27273: *8 client sent invalid method while reading client pipelined request line, client: 192.168.72.2, server: _, request: "bar"
需要解决的问题:如何避免Nginx返回第二个400响应?
解决方案
可以通过调整Nginx配置,让服务器在检测到请求错误后直接终止连接或停止处理剩余数据,避免误判剩余内容为新请求。以下是几种可行方案:
方案1:强制一次性读取整个请求体
在http或server块中添加以下配置:
client_body_in_single_buffer on; client_body_buffer_size 8k; # 根据业务实际调整缓冲区大小,确保能容纳正常请求体
该配置让Nginx将整个请求体加载到单个缓冲区中,一旦检测到Content-Length与实际请求体长度不匹配,会直接返回400错误并关闭连接,不会将剩余内容当作新请求处理。
方案2:返回404时强制关闭连接
在对应的location块中修改返回规则:
location / { try_files $uri $uri/ =404; return 404 close; }
此方法在返回404后立即关闭连接,服务器不会再读取后续的请求数据,从而避免产生第二个响应。但会牺牲HTTP连接复用的性能,适合对连接复用要求不高的场景。
方案3:缩短请求体读取超时时间
在http或server块中添加:
client_body_timeout 2s;
缩短请求体读取的超时时间,让服务器在处理无效请求时更快关闭连接,减少误判剩余内容的概率,属于辅助优化手段。
内容的提问来源于stack exchange,提问作者airween
相关产品推荐
相关产品推荐

