Nginx上游发送太大的标头,同时从上游读取响应标头

时间:2020-01-09 10:42:48  来源:igfitidea点击:

我收到以下错误,我的应用程序停止运行:

*2020/07/12 14:32:03 \[error\] 45625#45625: \*10918 **upstream sent too big header while reading response header from upstream**, client: 139.xxx.yyy.zzz, server: www.theitroad.com, request: “POST /app/mg/posts HTTP/2.0”, upstream: “fastcgi://unix:/run/php/php-fpm.sock:”, host: “www.theitroad.com”, referrer: “https://www.theitroad.com/mg/admin/index.app”*  
 How do I fix this error for Nginx web server running on Linux or Unix-like systems?

如何为在Linux或者类Unix系统上运行的Nginx Web服务器解决此错误?
本教程说明如何解决Nginx错误,即在Linux或者Unix系统上从上游读取响应头时,上游发送了太大的头。

Nginx上游发送太大的标头,同时从上游读取响应标头

为PHP/Python/Perl和其他应用程序配置了在反向代理模式下使用Nginx或者FastCGI导致的此错误。
您需要启用代理服务器响应的缓冲。

Nginx旨在加速请求。
因此,它将缓冲对后端服务器(如Apache)或者FastCGI进程(如PHP-FPM)发出的所有请求。
默认情况下,缓冲区大小等于一个内存页。
例如,4K或者8K,取决于操作系统。
如果发送了更多信息,nginx会在您的日志文件中出现错误:

$ tail -f /var/log/nginx/www.theitroad.com_error.log
upstream sent too big header while reading response header from upstream

修复Nginx在代理/反向代理模式下运行时的问题

编辑您的nginx.conf或者虚拟域文件:

$ sudo vi /etc/nginx/vhosts.d/theitroad.com.conf

在http或者服务器或者位置contaxt中设置以下内容:

server {
proxy_busy_buffers_size   512k;
proxy_buffers   4 512k;
proxy_buffer_size   256k;
# rest of nginx config #
}

确保测试并重新加载nginx服务器:

# nginx -t
# nginx -s reload

其中:

  • proxy_busy_buffers_size:启用对来自代理服务器的响应的缓冲时,限制了在尚未完全读取响应时可以忙于向客户端发送响应的缓冲区的总大小。同时,其余缓冲区可用于读取响应,并在需要时将部分响应缓冲到临时文件中。默认情况下,大小受proxy_buffer_size和proxy_buffers指令设置的两个缓冲区的大小限制。
  • proxy_buffers:为单个连接设置用于从代理服务器读取响应的缓冲区的数量(4)和大小(512k)。
  • proxy_buffer_size:设置用于读取从代理服务器接收到的响应的第一部分的缓冲区的大小。

我可以关闭代理缓冲吗?

是的,但出于性能原因,我不建议您这样做。
但是,以下是关闭它的配置指令:

######################################################################################
## 'proxy_buffering off|on;' must be set in http, or server, or location directives ##
######################################################################################
http {
    proxy_buffering off;
    # rest of config
}

处理proxy_pass和fastcgi缓冲区

考虑以下PHP-fmp配置:

## set php as server path ##
upstream php {
  server unix:/run/php/php-fpm.sock;
}
    # Pass all .php files onto a php-fpm/php-fcgi server.
     index index.php index.html;
     location ~ [^/]\.php(/|$) {
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      fastcgi_pass php;
      fastcgi_split_path_info ^(.+?\.php)(/.*)$;
            if (!-f $document_root$fastcgi_script_name) {
                     return 404;
     }

我们需要在fastcgi_pass之后追加以下指令:

fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_pass php;
    ## TUNE buffers to avoid error ##  
    fastcgi_buffers 16 32k;
    fastcgi_buffer_size 64k;
    fastcgi_busy_buffers_size 64k;

其中:

  • ``fastcgi_buffers`:为单个连接设置用于从FastCGI服务器读取响应的缓冲区的数量(16)和大小(32k)
  • fastcgi_buffer_size`:我们可以设置用于读取从FastCGI服务器接收到的响应的第一部分的缓冲区的大小。
  • ``fastcgi_busy_buffers_size`:当启用来自FastCGI服务器的响应缓冲时,限制在尚未完全读取响应时可以忙于向客户端发送响应的缓冲区的总大小。同时,其余的缓冲区用于读取响应,并在需要时将响应的一部分缓冲到临时文件中。

我可以关闭fastcgi缓冲吗?

同样,是的,但是出于性能原因,我不建议您将其关闭。
但是,以下是配置指令供您随时参考:

##
## Enables or disables buffering of responses from the FastCGI server ##
## Must be set in http, server, location contaxt 
## fastcgi_buffering on | off;
##
location / {
   fastcgi_buffering off;
   # rest of config below #
}

我可以同时结合使用fastcgi和代理缓冲吗?

是的,为了安全起见,我在http contaxt中添加了以下内容:

http {
fastcgi_buffers 16 32k;
fastcgi_buffer_size 64k;
fastcgi_busy_buffers_size 64k;
proxy_buffer_size   128k;
proxy_buffers   4 256k;
proxy_busy_buffers_size   256k;
# rest of config #
}

其他建议

确保上游PHP/Python/Perl/Ruby服务器没有崩溃。
检查上游Apache服务器是否将无效的标头发送回Nginx。
确保您的服务器不受DoS/DDoS攻击。
这些会导致许多错误和缓冲区溢出。
始终使用cat命令/grep命令/tail命令查看后端/上游服务器日志文件中的线索:

$ tail -f /path/to/apache.log
$ grep -i error /var/log/nginx/error.log
$ egrep -i 'error|cri' /var/log/nginx/php.error.log