如何避免 nginx “上游发送的标头太大”错误?

Posted

技术标签:

【中文标题】如何避免 nginx “上游发送的标头太大”错误?【英文标题】:How to avoid nginx "upstream sent too big header" errors? 【发布时间】:2011-01-19 10:01:26 【问题描述】:

我正在运行 nginx、Phusion Passenger 和 Rails。

我遇到了以下错误:

upstream sent too big header while reading response header from upstream, client: 87.194.2.18, server: xyz.com, request: "POST /user_session HTTP/1.1", upstream: "passenger://unix:/tmp/passenger.3322/master/helper_server.sock

它发生在对 Facebook Connect 的身份验证调用的回调中。

谷歌搜索后,尝试更改包括 proxy_buffer_size 和 large_client_header_buffers 在内的 nginx 设置无效。

如何调试?

【问题讨论】:

【参考方案1】:

尝试将其添加到配置中:

http 
    ...
    proxy_buffers 8 16k;
    proxy_buffer_size 32k;
    

【讨论】:

因为他在 nginx 上使用 Phusion Passenger,你的解决方案对他没有帮助。因为他上面引用的错误消息来自乘客本身,几乎肯定不是直接来自 nginx。但是,仍然按照您所说的进行操作可能是安全的,但还要添加两个乘客吊坠(passenger_buffers 和乘客缓冲区大小),如下所述。 @trapni 可能无法帮助回答这个问题,但也是其他人使用 nginx 代理的解决方案 解决了我使用 nginx 反向代理到 apache2 的问题。谢谢:) 优胜者鸡肉晚餐【参考方案2】:

也许添加它会使其工作,您如何连接到上游? http、fastcgi 还是其他?

http 
    ...
    fastcgi_buffers 8 16k;
    fastcgi_buffer_size 32k;

【讨论】:

phusion 乘客根本没有使用 fastcgi,它是 nginx 进程的直接部分,所以这对他的情况毫无帮助。 天哪!你是绝对正确的,我这边的愚蠢错误:) 谢谢。它非常适合我的 fastcgi 实现。 这对我的 Wordpress nGinX 配置有两个帮助。 非常适合 php-fpm 标头问题。【参考方案3】:

最近遇到这个错误。

由于Passenger 3.0.8 现在有一个设置允许您设置缓冲区和缓冲区大小。所以现在你可以做

http 
    ...
    passenger_buffers 8 16k;
    passenger_buffer_size 32k;

这为我解决了问题。

【讨论】:

【参考方案4】:
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;

【讨论】:

【参考方案5】:

这是我在过去 2 年中对这个错误的理解:

upstream sent too big header while reading response header from upstream 是 nginx 表达“我不喜欢我所看到的”的通用方式

    您的上游服务器线程崩溃了 上游服务器发回了无效的标头 从 STDERR 发回的通知/警告破坏了它们的缓冲区,并且它和 STDOUT 都已关闭

3:查看消息上方的错误日志,它是否在消息之前记录了行? PHP message: PHP Notice: Undefined index: 来自循环我的日志文件的示例 sn-p:

2015/11/23 10:30:02 [error] 32451#0: *580927 FastCGI sent in stderr: "PHP message: PHP Notice:  Undefined index: Firstname in /srv/www/classes/data_convert.php on line 1090
PHP message: PHP Notice:  Undefined index: Lastname in /srv/www/classes/data_convert.php on line 1090
... // 20 lines of same
PHP message: PHP Notice:  Undefined index: Firstname in /srv/www/classes/data_convert.php on line 1090
PHP message: PHP Notice:  Undefined index: Lastname in /srv/www/classes/data_convert.php on line 1090
PHP message: PHP Notice:
2015/11/23 10:30:02 [error] 32451#0: *580927 FastCGI sent in stderr: "ta_convert.php on line 1090
PHP message: PHP Notice:  Undefined index: Firstname

您可以在第 3 行(从之前的 20 个错误中)看到缓冲区限制被击中、破坏,并且下一个线程在它上面写入。 Nginx 然后关闭连接并返回 502 给客户端。

2:记录每个请求发送的所有标头,检查它们并确保它们符合标准(nginx 不允许超过 24 小时的任何内容删除/过期 cookie,发送无效的内容长度,因为错误消息在内容计数...)

示例包括:

<?php
//expire cookie
setcookie ( 'bookmark', '', strtotime('2012-01-01 00:00:00') );
// nginx will refuse this header response, too far past to accept
....
?>

还有这个:

<?php
header('Content-type: image/jpg');
?>

<?php   //a space was injected into the output above this line
header('Content-length: ' . filesize('image.jpg') );
echo file_get_contents('image.jpg');
// error! the response is now 1-byte longer than header!!
?>

1:验证或制作脚本日志,以确保您的线程到达正确的终点并且在完成之前不会退出。

【讨论】:

【参考方案6】:

我想我会加入我的解决方案,因为我目前没有看到它列出。原来我无意中将一个大对象放入会话中,如下所示。

session["devise.#provider_data"] = env["omniauth.auth"]

只有当有人首先使用 GitHub OAuth 进行身份验证,然后尝试使用使用同一电子邮件的另一个社交个人资料进行身份验证时才会发生这种情况(为什么我最初无法找出问题所在)。

这是完整的OmniauthCallbacksController 供上下文参考:

class OmniauthCallbacksController < Devise::OmniauthCallbacksController

  def self.provides_callback_for(provider)
    class_eval %Q
      def #provider
        @user = User.from_omniauth(request.env["omniauth.auth"])
        if @user.persisted?
          sign_in_and_redirect @user, event: :authentication
          set_flash_message(:notice, :success, kind: "#provider".capitalize) if is_navigational_format?
        else
          auth = request.env["omniauth.auth"]
          if User.exists?(email: auth.info.email)
            set_flash_message(:notice, :failure, kind: "#provider".capitalize, reason: "email " + auth.info.email + " already exists") if is_navigational_format?
          else
            set_flash_message(:notice, :error, kind: "#provider".capitalize) if is_navigational_format?
          end
          session["devise.#provider_data"] = env["omniauth.auth"] <----- Remove this line
          redirect_to new_user_registration_path
        end
      end
    
  end

  [:github, :linkedin, :google_oauth2].each do |provider|
    provides_callback_for provider
  end
end

一旦我删除了违规行,一切都很好。我猜我把它放在那里是为了调试。

【讨论】:

以上是关于如何避免 nginx “上游发送的标头太大”错误?的主要内容,如果未能解决你的问题,请参考以下文章

从上游读取响应标头时如何修复上游发送的标头太大?

使用 Supervisor 启动 Celery 时如何避免 SECRET_KEY 错误?

请教关于nginx配置404错误页面

如何避免使用 Django、nginx 和 uWSGI 将环境变量放到多个地方?

从 Nginx 到 Pandownload,程序员如何避免面向监狱编程?

zabbix 监控nginx语法错误