:一种。摘要
作为标题,Guzzle允许一次发送多个请求以节省时间,如documentation。
$responses = $client->send(array(
$requestObj1,
$requestObj2,
...
));
(given that each request object is an instance of
Guzzle\Http\Message\EntityEnclosingRequestInterface)
当响应返回时,为了确定哪个响应针对哪个请求,我们可以遍历每个请求并获得响应(仅在执行上述命令后才可用):
$response1 = $requestObj1->getResponse();
$response2 = $requestObj2->getResponse();
...
B中。问题
如果请求对象包含相同的数据。无法识别原始请求。
假设我们有以下场景需要创建2篇文章:远程服务器上的A和B:something.com/articles/create.json
每个请求都有相同的POST数据:
subject: This is a test article
创建之后,Guzzle回复2位置回来:
something.com/articles/223.json
something.com/articles/245.json
使用上述方法链接对其请求的响应,我们仍然不知道哪个响应是针对哪篇文章的,因为请求对象完全相同。
因此在我的数据库中我无法写下结果:
article A -> Location: 245.json
article B -> Location: 223.json
因为它可能是另一种方式:
article A -> Location: 223.json
article B -> Location: 245.json
解决方案是在POST请求中添加一些额外的参数,例如
subject: This is a test article
record: A
然而,距离服务器将返回错误并且不会创建文章,因为它不理解密钥"记录"。距离服务器是第三方服务器,我不能改变它的工作方式。
另一个合适的解决方案是在请求对象上设置一些特定的id / tag,这样我们就可以在之后识别它。但是,我已查看了文档,但没有方法可以唯一地标识请求,如
$request->setID("id1")
or
$request->setTag("id1")
这已经困扰了我好几个月,仍然无法解决这个问题。
如果您有解决方案,请告诉我。
非常感谢,并且你救了我!!!!
感谢您阅读这篇长篇文章。
答案 0 :(得分:1)
我遇到了同样的问题。
我通过添加一个自定义查询参数来解决这个问题,该参数具有为每个请求生成的唯一ID,并将其添加到请求网址中(您需要记住每个ID以便在之后解决它)。
在$responses = $client->send($requests)
之后,您可以遍历响应并检索有效网址$response->getEffectiveUrl()
并对其进行解析(请参阅parse_url和parse_str)以获取自定义参数(使用唯一ID)并搜索您拥有它的请求数组。
答案 1 :(得分:1)
我找到了正确的方法,Guzzle允许在请求完成后添加回调。因此,我们可以通过在批处理中的每个请求上设置它来实现这一点
默认情况下,每个请求都可以像这样创建
$request = $client->createRequest('GET', 'http://httpbin.org', [
'headers' => ['X-Foo' => 'Bar']
]);
所以,要实现我们想要的目标:
$allRequests = [];
$allResults = [];
for($k=0; $k<=10; $k++){
$allRequests['key_'.$k] = $client->createRequest('GET', 'http://httpbin.org?id='.$k, [
'headers' => ['X-Foo' => 'Bar'],
'events' => [
'complete' => function ($e) use (&$allResults, $k){
$response = $e->getResponse();
$allResults['key_'.$k] = $response->getBody().'';
}
]
]);
}
$client->sendAll(array_values($allRequests));
print_r($allResults);
所以现在$ allResults对每个相应的请求都有结果。
e.g。 $ allResults [&#39; key_1&#39;]是$ allRequests [&#39; key_1&#39;]
的结果答案 2 :(得分:1)
我找到了一个更好的答案。
我一次发送了20个请求批次,同时发送了4个请求,并使用了我实现的汇集技术,并在文档中拒绝了。
我发现我可以在requestAsync()函数调用结束时添加这段代码,在生成/构建数组时(我在不同的地方都这样做)。
$request = $request->then(function (\GuzzleHttp\Psr7\Response $response) use ($source_db_object) {
$response->_source_object = $source_db_object;
return $response;
});
然后在池中的clousures中,我可以正常访问响应中的_source_object,并且效果很好。 我发现它有点hacky,但是如果你确定使用的名字永远不会与Guzzle中的任何东西发生冲突,那应该没问题。
以下是一个完整的例子:
use GuzzleHttp\Client;
use GuzzleHttp\Pool;
use GuzzleHttp\Psr7\Response as GuzzleResponse;
$client = new Client();
$requests = [];
// Simple set-up here, generate some random async requests
for ($i = 0; $i < 10; $i++) {
$request = $client->requestAsync('GET', 'https://jsonplaceholder.typicode.com/todos/1');
// Here we can attach any identifiable data
$request->_source_object = $i;
array_push($requests, $request);
}
$generator = function () use($requests) {
while ($request = array_pop($requests)) {
yield function() use ($request) {
return $request->then(function (GuzzleResponse $response) use ($request) {
// Attach _source_object from request to the response
$response->_source_object = $request->_source_object ?? [];
return $response;
});
};
}
};
$requestPool = new Pool($client, $generator(), [
'concurrency' => 5,
'fulfilled' => function ($response) {
// Then we can properly access the _source_object data once response has arrived here!
echo $response->_source_object . "\n";
}
]);
$requestPool->promise()->wait();
答案 3 :(得分:0)
我是这样做的:
id <- factor("384508338244525230_47603942")
(id_ <- as.numeric(sub("([0-9]+)_.*", "\\1", id)))
# [1] 3.845083e+17
format(id_, scientific = FALSE)
# [1] "384508338244525230"
答案 4 :(得分:0)
与新GuzzleHttp相关的更新 guzzlehttp / guzzle
并发/并行调用现在通过几种不同的方法运行,包括Promises .. Concurrent Requests
传递RequestInterfaces数组的旧方法将不再适用。
请参阅示例此处
$newClient = new \GuzzleHttp\Client(['base_uri' => $base]);
foreach($documents->documents as $doc){
$params = [
'language' =>'eng',
'text' => $doc->summary,
'apikey' => $key
];
$requestArr[$doc->reference] = $newClient->getAsync( '/1/api/sync/analyze/v1?' . http_build_query( $params) );
}
$time_start = microtime(true);
$responses = \GuzzleHttp\Promise\unwrap($requestArr); //$newClient->send( $requestArr );
$time_end = microtime(true);
$this->get('logger')->error(' NewsPerf Dev: took ' . ($time_end - $time_start) );
在此示例中,您将能够使用 $ requestArr [$ doc-&gt; reference] 引用每个回复。简而言之,为数组提供索引并运行Promise :: unwrap调用。
答案 5 :(得分:0)
我也遇到过这个问题。这是第一个线程。我知道这是一个已解决的线程,但是我最终想出了一个更好的解决方案。这适用于所有可能遇到此问题的人。
其中一种选择是使用Guzzle Pool :: batch。
批处理的作用是,它将合并请求的结果推送到数组中并返回该数组。这样可以确保响应和请求的顺序相同。
$client = new Client();
// Create the requests
$requests = function ($total) use($client) {
for ($i = 1; $i <= $total; $i++) {
yield new Request('GET', 'http://www.example.com/foo' . $i);
}
};
// Use the Pool::batch()
$pool_batch = Pool::batch($client, $requests(5));
foreach ($pool_batch as $pool => $res) {
if ($res instanceof RequestException) {
// Do sth
continue;
}
// Do sth
}