Как прочитать эффективный URL-адрес ответа в Guzzle ~ 6.0

Я искал около 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://stackoverflow.com/a/35443523/1811887

Спасибо @YauheniPrakopchyk


person joserobleda    schedule 06.06.2015    source источник


Ответы (6)


Решение 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
person Yauheni Prakopchyk    schedule 16.02.2016
comment
Итак, похоже, это что-то вроде предложенного @Евгений, но встроенного, верно? - person joserobleda; 18.02.2016
comment
@joserobleda, это очень трудно читать. Я бы предпочел отключить перенаправления и проверить заголовок местоположения этому обилию кода. - person Yauheni Prakopchyk; 18.02.2016
comment
Вот почему я отметил ваш ответ как правильный ответ. Для меня пока лучшее решение. - person joserobleda; 18.02.2016
comment
пришлось отредактировать TransferStats на \GuzzleHttp\TransferStats - person MolteNolte; 22.04.2020
comment
исправлено. - person Gras Double; 14.07.2020

Вы можете проверить, какие перенаправления были в вашем запросе, установив параметр 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));

Если были какие-либо перенаправления, последним должен быть ваш эффективный URL-адрес, в противном случае ваш первоначальный URL-адрес.

Подробнее о allow_redirects можно прочитать здесь http://docs.guzzlephp.org/en/latest/request-options.html#allow-redirects.

person bgaluszka    schedule 16.11.2015

Я использую промежуточное программное обеспечение для отслеживания запросов в цепочке перенаправления и сохранения последнего. 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://stackoverflow.com');
$response = $client->send($request);
var_dump($lastRequest->getUri()->__toString());

Результат:

string(24) "http://stackoverflow.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://stackoverflow.com');
$response = $client->send($request);
var_dump($effectiveYrlMiddleware->getLastRequest()->getUri()->__toString());
person Евгений Грицай    schedule 08.07.2015
comment
Выглядит хорошо, я бы хотел, чтобы было меньше кода, но я действительно не думаю, что есть лучший подход. - person joserobleda; 09.07.2015

Я думаю, что лучше всего использовать заголовки ответов для хранения этой информации. Я написал простой класс, который сохраняет эффективный URL-адрес в заголовке X-GUZZLE-EFFECTIVE-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');
person Artur Bodera    schedule 12.08.2015

Принятый ответ не сработал для меня, но привел меня в путь:

$client = new \GuzzleHttp\Client();
$client->request('GET', $url, [
    'on_stats' => function (\GuzzleHttp\TransferStats $stats) {
        echo($stats->getHandlerStats()['redirect_url']);
    }
]);
person Sebastien Horin    schedule 16.02.2017
comment
Принятый ответ не сработал для меня, как и этот. Я не понимаю, как они могут работать, поскольку запросы CURL являются асинхронными и будут выполняться после завершения исходного PHP-запроса (так что вы делаете запрос к некоторому URL-адресу и повторяете/получаете переменную после запрос выполнен, но отображение/доступ к переменной из начального потока...). Что сработало для меня, так это простое изменение эха на использование Monolog. Может быть, это зависит от настройки Guzzle, idk - person eithed; 25.04.2018
comment
запросы синхронны. Следующая строка кода выполняется после завершения запроса. - person Flame; 20.08.2018

Я не эксперт в этом вопросе, но, насколько я понимаю, эффективный URL-адрес не определяется в общем HTTP-сообщении. Я думаю, что это связано с Curl, и поскольку Guzzle может использовать любой обработчик HTTP для отправки запросов (см. здесь), информация не обязательно присутствует.

person marcosh    schedule 06.06.2015
comment
Понятно, но должен же быть какой-то механизм, позволяющий мне получить эту информацию, не так ли? - person joserobleda; 07.06.2015
comment
вы, вероятно, могли бы использовать что-то вроде этого: php.net/manual/en/function. curl-getinfo.php, или, может быть, попробуйте открыть проблему в репозитории guzzle и попросить помощи там - person marcosh; 08.06.2015
comment
На данный момент я могу отключить перенаправления и прочитать заголовок Location, но это допустимо только в моем текущем сценарии. Когда вы получаете больше перенаправлений, это не вариант. - person joserobleda; 08.06.2015