業(yè)務場景:webman開發(fā),提供一個給用戶端調用的api接口,實現(xiàn)邏輯如下:
1、把用戶提交的數(shù)據(jù)處理下,然后請求若干個三方系統(tǒng)的http接口
2、根據(jù)這些三方接口返回的內容,來生成api接口響應數(shù)據(jù)
比如,有3個三方接口A、B、C,都有可能返回我想要的數(shù)據(jù)
如果A響應最快,返回了['IS_A'=> true, 'A DATA' => '...'],那么就直接拿'A DATA'處理下生成接口響應數(shù)據(jù)。B、C的響應結果直接丟棄不用
如果A響應最快,但是返回了['IS_A' => false],那么就繼續(xù)等待下一個最先響應、并且'IS_X'是true的三方接口
現(xiàn)在要求就是這個api接口,性能要高,速度要快(假設這些三方接口本身響應都足夠快)
然后搜了下站內很多帖子,都是推薦用workerman/http-client
但是我不太清楚,怎么才能最好的實現(xiàn)我想要的效果
已經用了workermanV5、http-client2.0、revolt/event-loop
<?php
namespace app\controller;
use support\Request;
class ApiController
{
public function index(Request $request)
{
$http = new \Workerman\Http\Client();
// 怎么實現(xiàn)下面代碼的業(yè)務
// 但是三方接口1,和三方接口2能同時請求,節(jié)省時間
// 哪個先返回我想要的結果,接口就響應哪個數(shù)據(jù)
$resp1 = $http->get('三方接口1');
$data1 = json_decode($resp1->getBody(), true);
if ($data1['success']) {
return json(['data' => $data1['data']]);
}
$resp2 = $http->get('三方接口2');
$data2 = json_decode($resp2->getBody(), true);
if ($data2['success']) {
return json(['data' => $data2['data']]);
}
return json(['data' => null]);
}
}
這種情況用curl_multi就可以,下面代碼是讓webman AI的gpt4生成的,你試下
<?php
// 要請求的URL列表
$urls = [
'http://example.com',
'http://example.org',
'http://example.net'
];
// 初始化多個CURL句柄
$multiCurl = curl_multi_init();
$curlArray = array();
foreach ($urls as $i => $url) {
$curlArray[$i] = curl_init($url);
curl_setopt($curlArray[$i], CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($multiCurl, $curlArray[$i]);
}
// 執(zhí)行批處理句柄
$index=null;
do {
while (($execrun = curl_multi_exec($multiCurl, $index)) == CURLM_CALL_MULTI_PERFORM);
if ($execrun != CURLM_OK) break;
// 一旦有一個請求完成,找出是哪個請求
while ($done = curl_multi_info_read($multiCurl)) {
// 獲取信息和內容
$info = curl_getinfo($done['handle']);
if ($info['http_code'] == 200) {
$output = curl_multi_getcontent($done['handle']);
//關閉句柄
foreach ($urls as $i => $url) {
curl_multi_remove_handle($multiCurl, $curlArray[$i]);
curl_close($curlArray[$i]);
}
curl_multi_close($multiCurl);
// 返回獲取的輸出
return $output;
}
}
// 如果沒有請求完成,就暫時掛起連接
if ($index > 0) {
curl_multi_select($multiCurl);
}
} while ($index > 0);
// 如果所有請求都沒有成功,關閉CURL句柄并返回false
foreach ($urls as $i => $url) {
curl_multi_remove_handle($multiCurl, $curlArray[$i]);
curl_close($curlArray[$i]);
}
curl_multi_close($multiCurl);
return false;
謝謝解答,我先試下。
請問我的這種需求,沒必要用workerman/http-client么?
搜了站內一些帖子,感覺我的需求跟這個好像差不多,不是用異步協(xié)程http可以提高性能么
http://m.wtbis.cn/q/11997
異步或者協(xié)程性能好一些,但是要求業(yè)務不能使用全局變量(包括靜態(tài)成員)存儲請求相關的狀態(tài)數(shù)據(jù),否則會導致邏輯錯亂。
下面是webman協(xié)程用法
public function index(Request $request)
{
$urls = [
'https://www.163.com',
'https://www.bing.com',
'https://example.com'
];
$http = new \Workerman\Http\Client();
$suspension = EventLoop::getSuspension();
foreach ($urls as $url) {
$http->get($url, function ($response) use ($suspension, $http) {
$data = (string)$response->getBody();
if (strpos($data, 'Example Domain')) { // 假設返回中必須有Example Domain才算成功
$suspension->resume($data);
}
});
}
$data = $suspension->suspend();
return response($data);
}
Error: Must call suspend() before calling resume() in /home/web/webman-co/vendor/revolt/event-loop/src/EventLoop/Internal/DriverSuspension.php:52
Stack trace:
worker[webman:9729] exit with status 64000
這樣運行之后會報錯。
Must call suspend() before calling resume() 意思是你必須在resume()被調用之前調用suspend(),你檢查下你的代碼。
如果搞不懂就用curl_multi