php はプログラムを実行しますが、数ミリ秒で完了する場合もあれば、長時間かかる場合もあります。
たとえば、ユーザーが注文を行う場合、電子メール、テキスト メッセージ、プッシュ通知などを送信するために一部のサードパーティ サービスが呼び出される場合、フロントエンドは待たされる可能性があります。
これらの時間のかかるスクリプトは、実行される限り、戻り結果を気にしないことがあります。このとき、非同期で実行する必要があります。
ご存知のとおり、PHP はマルチスレッドを直接サポートしていません。妥協した方法でそれを行うこともできます。ここで重要なのは fsockopen
です。
fsockopen を通じてリクエストを送信し、返された結果を無視すると、プログラムはすぐに戻ることができます。
サンプル コード:
$fp = fsockopen("www.example.com", 80, $errno, $errstr, 30); if (!$fp) { echo "$errstr ($errno)<br />\n"; } else { $out = "GET /backend.php HTTP/1.1\r\n"; $out .= "Host: www.example.com\r\n"; $out .= "Connection: Close\r\n\r\n"; fwrite($fp, $out); /*忽略执行结果 while (!feof($fp)) { echo fgets($fp, 128); }*/ fclose($fp); }
ヘッダー情報を手動で入力する必要があることに注意してください。コメントセクションを開くと、リクエストの戻り結果が表示されますが、プログラムは戻り結果を待って終了するため、今回は再び同期になります。
実際にテストしてみたところ、実行結果を無視しなければデバッグ時に毎回sockリクエストは正常に送信されるのですが、実行結果を無視するとsockリクエストが送信されないことが多いことが分かりました。成功しました。 nginx ログを確認すると、ステータス コード 499 のリクエストが多数見つかります。
後で理由がわかりました。
fwrite
は fclose
の直後に実行され、nginx は直接 499 を返します。リクエストは処理のために php に転送されます。
クライアントがアクティブ ポートを介して接続をリクエストした場合、NGINX はリクエストを上流のサービス (FastCGI PHP プロセス) にプロキシしません。このとき、リクエストはアクセス ログに 499 として記録されます。
解決策:
1) nginx.conf に構成を追加します。
# 忽略客户端中断 fastcgi_ignore_client_abort on;
2) fwrite の後に usleep を使用します。関数は 20 ミリ秒スリープします:
usleep(20000);
その後のテストでは障害は見つかりませんでした。
完全なコードを添付します:
<?php /** * 工具类 * */ class FsockService { public static function post($url, $param){ $host = parse_url($url, PHP_URL_HOST); $port = 80; $errno = ''; $errstr = ''; $timeout = 30; $data = http_build_query($param); // create connect $fp = fsockopen($host, $port, $errno, $errstr, $timeout); if(!$fp){ return false; } // send request $out = "POST ${url} HTTP/1.1\r\n"; $out .= "Host:${host}\r\n"; $out .= "Content-type:application/x-www-form-urlencoded\r\n"; $out .= "Content-length:".strlen($data)."\r\n"; $out .= "Connection:close\r\n\r\n"; $out .= "${data}"; fwrite($fp, $out); //忽略执行结果;否则等待返回结果 // if(APP_DEBUG === true){ if(false){ $ret = ''; while (!feof($fp)) { $ret .= fgets($fp, 128); } } usleep(20000); //fwrite之后马上执行fclose,nginx会直接返回499 fclose($fp); } public static function get($url, $param){ $host = parse_url($url, PHP_URL_HOST); $port = 80; $errno = ''; $errstr = ''; $timeout = 30; $url = $url.'?'.http_build_query($param); // create connect $fp = fsockopen($host, $port, $errno, $errstr, $timeout); if(!$fp){ return false; } // send request $out = "GET ${url} HTTP/1.1\r\n"; $out .= "Host:${host}\r\n"; $out .= "Connection:close\r\n\r\n"; fwrite($fp, $out); //忽略执行结果;否则等待返回结果 // if(APP_DEBUG === true){ if(false){ $ret = ''; while (!feof($fp)) { $ret .= fgets($fp, 128); } } usleep(20000); //fwrite之后马上执行fclose,nginx会直接返回499 fclose($fp); } } ?>
関連する php の知識については、php チュートリアル をご覧ください。
以上がPHP で fsockopen を使用して非同期リクエストを実装する (コード例)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。