Symfony 4.3 PHP:如何从 302 重定向响应中读取 cookie?

我想做什么(在控制器中)

  1. 接收请求,基于该请求

  2. 发送外部 HTTP 请求

  3. 解析响应,基于

  4. 返回响应

我计划有多个功能都遵循这种模式。他们一个接一个地被调用。

Symfony 4.3 引入了 HttpClient 组件和 BrowserKit 组件,乍一看似乎符合要求。但事实证明,事情变得更加复杂。外部 HTTP 请求被发送到使用 cookie 跟踪会话的服务器,这应该不会太不寻常。如果在没有 cookie 的情况下发送请求,服务器总是以相同的登录页面内容进行响应。所以我们需要cookie。不用担心,对初始请求的响应带有一个“Set-Cookie”标头,其中包含在后续请求中在“Cookie”标头中发送的 cookie。带有 cookie 的响应的 HTTP 状态是“302 Found”,它在正常的 Web 环境中,使用 Web 浏览器重定向到请求中具有相同 cookie 的下一个页面。在我的 Symfony 控制器中复制这个动作似乎非常棘手。扩展我现在想做的第 2 步:

2.a. 发送外部 HTTP 请求

2.b. 从 302 响应中读取 cookie(不带自动重定向)

2.c. 设置后续请求的“Cookie”头,值来自2.b。

2.d. 将请求发送到新目标(在 302 响应的“Location”标头中设置)

这是控制器中的一些代码:

use Symfony\Component\HttpClient\HttpClient;

use Symfony\Component\HttpClient\Exception\RedirectionException;

use Symfony\Component\HttpFoundation\JsonResponse;


public function init(Request $request): JsonResponse

{

    $url = "external url";

    $client = HttpClient::create();

    try {

        $response = $client->request('GET', $url, [

            'max_redirects' => -1

        ]);

    } catch (RedirectionException $redirectionException) {


    }

    return new JsonResponse([], 200);

}

不设置 max_redirects 意味着客户端遵循重定向并最终返回 200 响应而没有任何 cookie。将该值设置为 -1 将引发重定向异常,并且带有 cookie 的 302 响应似乎丢失了。


我也试过 HttpBrowser 组件:


$cookieJar = new CookieJar();

$client = new HttpBrowser(HttpClient::create(), null, $cookieJar);

$client->request('GET', $url);

但是我得到了一个没有 cookie 的 200 响应,因为它会自动跟随重定向。


我知道这里提到的组件是 Symfony 4.3 的新组件并且是“实验性的”,但我也不认为我的任务过于复杂或不寻常。但也许 Symfony 有其他的 http 客户端更适合这项任务?


繁花如伊
浏览 360回答 1
1回答

芜湖不芜

事实证明,通过为 Symfony 尝试其他 HTTP 客户端组件而不是本机组件,这个任务更容易完成。所以我暂时把 Symfony HttpClient 和 HttpBrowser 放在一边。我设法用 guzzlehttp/guzzle 6.3.3 版解决了这个问题。这是我的控制器功能中的样子:use GuzzleHttp\Client;use Symfony\Component\HttpFoundation\Cookie;use Symfony\Component\HttpFoundation\JsonResponse;use Symfony\Component\HttpFoundation\Request;public function init(Request $request): JsonResponse {    $client = new Client([        'base_uri' => 'an external domain',        'cookies' => true    ]);    // get the 302 response, without following    $response = $client->get('path',[        'allow_redirects' => false    ]);    // get the cookie from the 302 response    $jar = new \GuzzleHttp\Cookie\CookieJar(true,[$response->getHeader('Set-Cookie')]);    // follow the redirect manually, with the cookie from the 302 response    $redirectResponse = $client->request('GET', $response->getHeader('Location')[0], [        'cookies' => $jar    ]);    $jsonResponse = new JsonResponse(['message' => 'my message'],200);    $originalCookie = Cookie::fromString($response->getHeader('Set-Cookie')[0]);    $newCookie = Cookie::create(        $originalCookie->getName(),        $originalCookie->getValue(),        $originalCookie->getExpiresTime(),        '/',        'my domain',        false,        true,        $originalCookie->isRaw(),        $originalCookie->getSameSite()    );    $jsonResponse->headers->setCookie($newCookie);    return $jsonResponse;}cookie 不能从响应中获取,否则它永远不会被发回,因为域或路径不匹配。因此,我创建了一个与原始 cookie 非常相似的新 cookie,然后将其发送回浏览器。这样 cookie 会在后续请求中返回,并且数据内容可以被转发。这里出现的其他问题是必须在外部服务器上处理的同源要求。我仍然对如何使用本地 Symfony 4.3 组件完成所有这些操作感兴趣,或者,如果有人可以确认这是不可能的。
打开App,查看更多内容
随时随地看视频慕课网APP