D 的个人博客

全职做开源,自由职业者

  menu

PHP 异步 HTTP 与 NGINX 499

PHP 异步 HTTP

在 PHP 代码中提交异步 HTTP 请求比较常用的方式是通过 fsockopen/fwrite/fclose 来实现,请参考如下代码。

 1function post($host, $path, $port, $data) {
 2    $post = http_build_query($data);
 3    $len = strlen($post);
 4
 5    $fp = fsockopen($host, $port, $errno, $errstr, 30);
 6    if (!$fp) {
 7        echo "$errstr ($errno)\n";
 8
 9        return;
10    }
11
12    $out = "POST $path HTTP/1.1\r\n";
13    $out .= "Host: $host\r\n";
14    $out .= "Content-type: application/x-www-form-urlencoded\r\n";
15    $out .= "Connection: Close\r\n";
16    $out .= "Content-Length: $len\r\n";
17    $out .= "\r\n";
18    $out .= $post . "\r\n";
19    // echo($out);
20    fwrite($fp, $out);
21
22    // 注释掉如下代码实现不等待 HTTP 响应,从而实现“异步”
23//    $receive = '';
24//    while (!feof($fp)) {
25//        $receive .= fgets($fp, 128);
26//    }
27//    echo "<br />" . $receive;
28
29
30    fclose($fp);
31}

这段代码可以如期完成异步 HTTP 效果,但是如果提交的服务端有 NGINX 做 CGI 反代的话,可能会导致上游后端 PHP 接收不到该请求。

NGINX 499

查看 NGINX access log,发现这样的请求会以 499(Client Closed Request)记录。确定问题是因为:客户端主动端口请求连接时,NGINX 不会将该请求代理给上游服务(FastCGI PHP 进程),这个时候 access log 中会以 499 记录这个请求。

要解决这个问题需要将 NGINX _FastCGI 忽略客户端中断_配置打开:

1fastcgi_ignore_client_abort on;

这样无论客户端是否断开,都会将这个请求代理给上游,并且会记录上游服务处理后的返回状态。

另外,还有一个类似配置 proxy_ignore_client_abort on;,这个配置是针对其他类型的反代,PHP 的场景并不适用。