Kubernetes Nginx入口控制器返回502,但仅用于AJAX / XmlHttpRequest请求

Aar*_*ron 0 nginx kubernetes

我有一个在nginx入口控制器后面运行Kubernetes的Web应用程序,它可以很好地用于请求浏览,但是来自浏览器的任何AJAX / XMLHTTPRequest都会从nginx收到502错误。

我捕获了常规和AJAX请求的HTTP标头,它们看起来都不错,正确的Host标头,协议等。我感到困惑,为什么只有XMLHttpRequest请求从nginx获取502。没有延迟/挂起,502是即时的。这些请求似乎永远不会到达应用程序,但会被nginx本身拒绝。将nginx切换为直接负载均衡器,问题就消失了。

我将进一步进行挖掘,但我想知道是否其他任何使用Nginx Ingress控制器的人之前都曾见过此问题并已解决?

我从nginx日志中选择了此错误,这表明容器对于nginx缓冲区返回的标头过大。但是我检查了nginx.conf并禁用了缓冲:'proxy_buffering off;'

2016/10/27 19:55:51 [error] 309#309: *43363 upstream sent too big header while reading response header from upstream, client: 10.20.51.1, server: foo.example.com, request: "GET /admin/pages/listview HTTP/2.0", upstream: "http://10.20.66.97:80/admin/pages/listview", host: "foo.example.com", referrer: "https://foo.example.com/admin/pages"
Run Code Online (Sandbox Code Playgroud)

奇怪的是,仅当XmlHttpRequest请求URL时,您才收到504错误。如果我使用curl请求相同的URL,它可以正常工作,并且响应标头如下。相同URL的AJAX / XmlHttpRequest会使响应头太大吗?

HTTP/1.1 200 OK
Server: nginx/1.11.3
Date: Thu, 27 Oct 2016 20:15:16 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 6596
Connection: keep-alive
X-Frame-Options: SAMEORIGIN
X-Powered-By: PHP/5.5.9-1ubuntu4.19
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: max-age=0, must-revalidate, no-transform, no-cache, no-store
Pragma: no-cache
X-Controller: CMSPagesController
X-Title: Example+Site+-+Pages
X-Frame-Options: SAMEORIGIN
Vary: X-Requested-With,Accept-Encoding,User-Agent
Strict-Transport-Security: max-age=15724800; includeSubDomains; preload
Run Code Online (Sandbox Code Playgroud)

Aar*_*ron 5

我解决了这个问题。仅XmlHttpRequests失败的原因是因为应用程序在看到XmlHttpRequest请求时具有特殊的行为,该请求在其中将约3000字节的额外标头转储到响应中。这使得总头大小大于默认的nginx头缓冲区。

nginx在大型HTTP标头有效载荷上阻塞很常见,因为它的默认缓冲区大小小于大多数其他Web服务器,只有4k或8k。解决这些错误的方法是,通过添加这些设置,将用于标头的缓冲区增加到16k。

proxy_buffers         8 16k;  # Buffer pool = 8 buffers of 16k
proxy_buffer_size     16k;    # 16k of buffers from pool used for headers
Run Code Online (Sandbox Code Playgroud)

Nginx文档非常模糊,这些设置含糊不清。据我了解,每个连接都有一个缓冲池。在这种情况下,每个有8个16k的缓冲区。这些缓冲区用于从上游Web服务器接收数据并将数据传递回客户端。

因此proxy_buffers确定池。然后proxy_buffer_size确定主机,该缓冲池的大部分可用于接收来自上游服务器的HTTP标头(四舍五入为我认为的整个缓冲区大小)。第三个设置proxy_busy_buffer_size确定有多少缓冲池可以忙于发送给客户端(我认为应四舍五入为整个缓冲区大小)。默认情况下,proxy_busy_buffer_size自动将其设置为池中的缓冲区数减去1。

因此,该proxy_buffers池必须足够大以适合,proxy_busy_buffer_size并且仍剩余足够的缓冲区以至少适合proxy_buffer_size上游Web服务器的for HTTP标头。

其净结果是,如果您完全增加proxy_busy_buffer_size,可能会立即得到令人困惑的错误:"proxy_busy_buffers_size" must be less than the size of all "proxy_buffers" minus one buffer,然后必须增加池的大小。

proxy_buffering off你问的设置是什么?好吧,这不会禁用代理缓冲!而是在将nginx发送到浏览器时是否将其缓冲到整个响应(缓冲池或磁盘),还是仅缓冲缓冲池中的缓冲区。因此,即使您打开off proxy_buffering代理缓冲,仍然会发生。

http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffer_size

http标头值的最大值?

我看到了一些建议,建议设置较大的缓冲池,例如8 x 512kb缓冲区(= 4MB)之类的大数字。每个连接都有一个缓冲池,因此,保留的缓冲池越小,可以处理的连接就越多。