如何在 Guzzle ~6.0 中读取响应有效 URL
Posted
技术标签:
【中文标题】如何在 Guzzle ~6.0 中读取响应有效 URL【英文标题】:How to read the response effective URL in Guzzle ~6.0 【发布时间】:2015-08-21 08:02:54 【问题描述】:我已经搜索了大约 2 个小时,但我无法弄清楚如何读取最终响应 uri。
在以前版本的 php Guzzle 中,您只需调用 $response->getEffectiveUrl()
即可。
我预计在新版本中会有类似的东西,所以最终代码如下所示:
$response = $httpClient->post('http://service.com/login', [
'form_params' => [
'user' => $user,
'padss' => $pass,
]
]);
$url = $response->getEffectiveUrl();
但在最新版本中 $response
现在是 GuzzleHttp\Psr7\Response
并且没有方法可以让我检索 uri。
我在此处 (http://guzzle.readthedocs.org/en/latest/quickstart.html#redirects) 阅读了有关重定向的信息,但没有提及
更新:6.1 版本现在允许您轻松地做到这一点:
https://***.com/a/35443523/1811887
感谢@YauheniPrakopchyk
【问题讨论】:
【参考方案1】:来自docs 的 Guzzle 6.1 解决方案。
use GuzzleHttp\Client;
use GuzzleHttp\TransferStats;
$client = new Client;
$client->get('http://some.site.com', [
'query' => ['get' => 'params'],
'on_stats' => function (TransferStats $stats) use (&$url)
$url = $stats->getEffectiveUri();
])->getBody()->getContents();
echo $url; // http://some.site.com?get=params
【讨论】:
所以,看起来这有点像 @Евгений 提议的,但是是内置的,对吧? @joserobleda 那一个很难阅读。我更喜欢关闭重定向并检查大量代码的位置标头。 这就是我将您的答案标记为有效回复的原因。对我来说是迄今为止最好的解决方案。 必须将 TransferStats 编辑为 \GuzzleHttp\TransferStats fixed.【参考方案2】:您可以通过设置track_redirects
参数来检查您的请求有哪些重定向:
$client = new \GuzzleHttp\Client(['allow_redirects' => ['track_redirects' => true]]);
$response = $client->request('GET', 'http://example.com');
var_dump($response->getHeader(\GuzzleHttp\RedirectMiddleware::HISTORY_HEADER));
如果有任何重定向,最后一个应该是您的有效网址,否则您的初始网址。
您可以在此处http://docs.guzzlephp.org/en/latest/request-options.html#allow-redirects 阅读有关allow_redirects
的更多信息。
【讨论】:
【参考方案3】:我正在使用中间件来跟踪重定向链中的请求并保存最后一个。最后一个请求的 uri 就是你想要的。
试试这个代码:
$stack = \GuzzleHttp\HandlerStack::create();
$lastRequest = null;
$stack->push(\GuzzleHttp\Middleware::mapRequest(function (\Psr\Http\Message\RequestInterface $request) use(&$lastRequest)
$lastRequest = $request;
return $request;
));
$client = new Client([
'handler' => $stack,
\GuzzleHttp\RequestOptions::ALLOW_REDIRECTS => true
]);
$request = new \GuzzleHttp\Psr7\Request('GET', 'http://httpbin.org/redirect-to?url=http://***.com');
$response = $client->send($request);
var_dump($lastRequest->getUri()->__toString());
结果:
string(24) "http://***.com"
类示例:
class EffectiveUrlMiddleware
/**
* @var \Psr\Http\Message\RequestInterface
*/
private $lastRequest;
/**
* @param \Psr\Http\Message\RequestInterface $request
*
* @return \Psr\Http\Message\RequestInterface
*/
public function __invoke(\Psr\Http\Message\RequestInterface $request)
$this->lastRequest = $request;
return $request;
/**
* @return \Psr\Http\Message\RequestInterface
*/
public function getLastRequest()
return $this->lastRequest;
$stack = \GuzzleHttp\HandlerStack::create();
$effectiveYrlMiddleware = new EffectiveUrlMiddleware();
$stack->push(\GuzzleHttp\Middleware::mapRequest($effectiveYrlMiddleware));
$client = new Client([
'handler' => $stack,
\GuzzleHttp\RequestOptions::ALLOW_REDIRECTS => true
]);
$request = new \GuzzleHttp\Psr7\Request('GET', 'http://httpbin.org/redirect-to?url=http://***.com');
$response = $client->send($request);
var_dump($effectiveYrlMiddleware->getLastRequest()->getUri()->__toString());
【讨论】:
看起来不错,我希望有更少的代码选项,但我真的不认为有更好的方法。【参考方案4】:我认为最好使用响应头来存储这些信息。我写了一个简单的类,在X-GUZZLE-EFFECTIVE-URL
header 中保存有效的url:
https://gist.github.com/Thinkscape/43499cfafda1af8f606d
用法:
<?php
use GuzzleHttp\Client;
use Thinkscape\Guzzle\EffectiveUrlMiddleware;
// Add the middleware to stack and create guzzle client
$stack = HandlerStack::create();
$stack->push(EffectiveUrlMiddleware::middleware());
$client = new Client(['handler' => $stack]);
// Test it out!
$response = $client->get('http://bit.ly/1N2DZdP');
echo $response->getHeaderLine('X-GUZZLE-EFFECTIVE-URL');
【讨论】:
【参考方案5】:接受的答案对我不起作用,但引导我前进:
$client = new \GuzzleHttp\Client();
$client->request('GET', $url, [
'on_stats' => function (\GuzzleHttp\TransferStats $stats)
echo($stats->getHandlerStats()['redirect_url']);
]);
【讨论】:
接受的答案对我不起作用,这个也不起作用。我不明白它们是如何工作的,因为 CURL 请求是异步的,并且会在初始 PHP 请求结束后发生(所以你正在向某个 URL 发出请求并在请求已完成,但变量的显示/访问来自初始线程......)。 did 对我有用的只是将 echo 更改为使用 Monolog。也许这取决于 Guzzle 设置,idk 请求是同步的。请求完成后执行下一行代码。【参考方案6】:For Guzzle 7:
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UriInterface;
$onRedirect = function(
RequestInterface $request,
ResponseInterface $response,
UriInterface $uri
)
echo 'Redirecting! ' . $request->getUri() . ' to ' . $uri . "\n";
;
$res = $client->request('GET', '/redirect/3', [
'allow_redirects' => [
'max' => 10, // allow at most 10 redirects.
'strict' => true, // use "strict" RFC compliant redirects.
'referer' => true, // add a Referer header
'protocols' => ['https'], // only allow https URLs
'on_redirect' => $onRedirect,
'track_redirects' => true
]
]);
echo $res->getStatusCode();
// 200
echo $res->getHeaderLine('X-Guzzle-Redirect-History');
// http://first-redirect, http://second-redirect, etc...
echo $res->getHeaderLine('X-Guzzle-Redirect-Status-History');
// 301, 302, etc...
【讨论】:
【参考方案7】:我不是该主题的专家,但据我了解,有效 url 不是一般 HTTP 消息中定义的内容。我认为这与 Curl 相关,因为 Guzzle 可以使用任何 HTTP 处理程序来发送请求 (see here),所以信息不一定存在。
【讨论】:
我明白了,但是应该有一个机制,无论如何,它可以让我获得这些信息,不是吗? 你可能会使用这样的东西:php.net/manual/en/function.curl-getinfo.php,或者尝试在 guzzle 存储库中打开一个问题并在那里寻求帮助 现在我可以禁用重定向并读取 Location 标头,但这仅在我当前的情况下有效。当您获得更多重定向时,这不是一个选择。以上是关于如何在 Guzzle ~6.0 中读取响应有效 URL的主要内容,如果未能解决你的问题,请参考以下文章
Guzzlehttp - 如何从 Guzzle 6 获取响应的正文?
你可以在 Guzzle POST Body 中包含原始 JSON 吗?
如何从 .NET Core 6.0 中的 JWT 安全令牌中读取自定义声明值