Nginx 499的問題


PHP 異步 HTTP 與 NGINX 499

PHP 異步 HTTP

在 PHP 代碼中提交異步 HTTP 請求比較常用的方式是通過 fsockopen/fwrite/fclose 來實現,請參考如下代碼。

function post($host, $path, $port, $data) { $post = http_build_query($data); $len = strlen($post); $fp = fsockopen($host, $port, $errno, $errstr, 30); if (!$fp) { echo "$errstr ($errno)\n"; return; } $out = "POST $path HTTP/1.1\r\n"; $out .= "Host: $host\r\n"; $out .= "Content-type: application/x-www-form-urlencoded\r\n"; $out .= "Connection: Close\r\n"; $out .= "Content-Length: $len\r\n"; $out .= "\r\n"; $out .= $post . "\r\n"; // echo($out); fwrite($fp, $out); // 注釋掉如下代碼實現不等待 HTTP 響應,從而實現“異步” // $receive = ''; // while (!feof($fp)) { // $receive .= fgets($fp, 128); // } // echo "<br />" . $receive; fclose($fp); } 

這段代碼可以如期完成異步 HTTP 效果,但是如果提交的服務端有 NGINX 做 CGI 反代的話,可能會導致上游后端 PHP 接收不到該請求。

NGINX 499

查看 NGINX access log,發現這樣的請求會以 499(Client Closed Request)記錄。確定問題是因為:客戶端主動端口請求連接時,NGINX 不會將該請求代理給上游服務(FastCGI PHP 進程),這個時候 access log 中會以 499 記錄這個請求。

要解決這個問題需要將 NGINX FastCGI 忽略客戶端中斷配置打開:

fastcgi_ignore_client_abort on; 

這樣無論客戶端是否斷開,都會將這個請求代理給上游,並且會記錄上游服務處理后的返回狀態。

另外,還有一個類似配置 proxy_ignore_client_abort on;,這個配置是針對其他類型的反代,PHP 的場景並不適用。

文章來源:https://hacpai.com/article/1444367397136?m=0

備注:fastcgi_ignore_client_abort on;雖然會忽略客戶端中斷,只是在nginx記錄中不記錄499記錄,並不能從根本上解決499問題。499有可能是客戶端關閉連接,也有可能是請求時間超過upstream_response_time的值,但是即便是upstream_response_time沒有值也會產生499,upstream_response_time 記錄的是從 Nginx 把請求轉發到后端服務器開始,到后端服務器響應到 Nginx 為止的時間。

upstream_response_time 沒有值有兩種情況:

1. 請求沒有被轉發到 upstream server

2. Nginx 在等待 upstream response 的時候,客戶端把連接關掉了,Nginx 也因此把跟 upstream 之間的連接關掉,所以不可能有 upstream response 被返回到 Nginx,自然也不會有 upstream_resposne_time.  在這種情況下,Nginx 會向客戶端返回 499 結合數據庫中有記錄來看,客戶端發起一個 http 請求, 請求到 NginxNginx 轉發給后端 PHPPHP 處理請求往數據庫插記錄,在這時,客戶端發起 abortNginx 斷開到 PHP 的連接,但是因為 PHP 已經發起了數據庫的操作,這個操作不會被中斷,所以記錄被成功插入到數據庫, Nginx 也向客戶端返回了 499 端口。

    就大多數場景而言,如果只有少量的nginx499是無關緊要的,很大一部分只是客戶端主動斷開了請求而已。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM