Symfony 4.3 PHP:如何从 302 重定向响应中读取 cookie?
Symfony 4.3 PHP: How to read the cookie from a 302 redirection response?
我想做什么(在控制器中)
- 收到一个请求,基于此
- 发送外部 HTTP 请求
- 解析响应,基于
- Return 回复
我计划有多个函数都遵循这个模式。一个接一个,接二连三地叫。
Symfony 4.3 引入了 HttpClient 组件和 BrowserKit 组件,乍一看似乎符合要求。但事实证明,事情变得更加复杂。外部 HTTP 请求被发送到一个服务器,该服务器使用 cookie 跟踪会话,这应该没什么特别的。如果发送请求时没有使用 cookie,服务器将始终以相同的着陆页内容进行响应。所以我们需要cookie。不用担心,对初始请求的响应带有 "Set-Cookie" header,其中包含在后续请求中 "Cookie" header 中发送的 cookie。带有 cookie 的响应的 HTTP 状态是“302 Found”,在正常的 web 环境中,使用 web 浏览器,重定向到请求中具有相同 cookie 的下一个页面。在我的 Symfony 控制器中复制这个动作似乎非常棘手。展开第 2 步。我现在想做的事情:
2.a。发送外部 HTTP 请求
2.b。从 302 响应中读取 cookie(没有自动重定向)
2.c。设置后续请求的"Cookie" header,值来自2.b.
2.d。将请求发送到新的目标(在302响应的"Location"header中设置)
这是来自控制器的一些代码:
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 意味着客户端遵循重定向并最终返回没有任何 cookie 的 200 响应。将值设置为 -1 将引发重定向
异常,并且 cookie 的 302 响应似乎丢失了。
我也试过 HttpBrowser 组件:
$cookieJar = new CookieJar();
$client = new HttpBrowser(HttpClient::create(), null, $cookieJar);
$client->request('GET', $url);
但是我收到了没有 cookie 的 200 响应,因为它会自动跟随重定向。
我知道这里提到的组件是 Symfony 4.3 和 "experimental" 的新组件,但我也不认为我的任务过于复杂或不寻常。但也许还有其他适用于 Symfony 的 http 客户端更适合这项任务?
事实证明,通过尝试 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 组件完成所有这些感兴趣,或者如果有人可以确认这是不可能的。
我想做什么(在控制器中)
- 收到一个请求,基于此
- 发送外部 HTTP 请求
- 解析响应,基于
- Return 回复
我计划有多个函数都遵循这个模式。一个接一个,接二连三地叫。
Symfony 4.3 引入了 HttpClient 组件和 BrowserKit 组件,乍一看似乎符合要求。但事实证明,事情变得更加复杂。外部 HTTP 请求被发送到一个服务器,该服务器使用 cookie 跟踪会话,这应该没什么特别的。如果发送请求时没有使用 cookie,服务器将始终以相同的着陆页内容进行响应。所以我们需要cookie。不用担心,对初始请求的响应带有 "Set-Cookie" header,其中包含在后续请求中 "Cookie" header 中发送的 cookie。带有 cookie 的响应的 HTTP 状态是“302 Found”,在正常的 web 环境中,使用 web 浏览器,重定向到请求中具有相同 cookie 的下一个页面。在我的 Symfony 控制器中复制这个动作似乎非常棘手。展开第 2 步。我现在想做的事情:
2.a。发送外部 HTTP 请求
2.b。从 302 响应中读取 cookie(没有自动重定向)
2.c。设置后续请求的"Cookie" header,值来自2.b.
2.d。将请求发送到新的目标(在302响应的"Location"header中设置)
这是来自控制器的一些代码:
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 意味着客户端遵循重定向并最终返回没有任何 cookie 的 200 响应。将值设置为 -1 将引发重定向 异常,并且 cookie 的 302 响应似乎丢失了。
我也试过 HttpBrowser 组件:
$cookieJar = new CookieJar();
$client = new HttpBrowser(HttpClient::create(), null, $cookieJar);
$client->request('GET', $url);
但是我收到了没有 cookie 的 200 响应,因为它会自动跟随重定向。
我知道这里提到的组件是 Symfony 4.3 和 "experimental" 的新组件,但我也不认为我的任务过于复杂或不寻常。但也许还有其他适用于 Symfony 的 http 客户端更适合这项任务?
事实证明,通过尝试 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 组件完成所有这些感兴趣,或者如果有人可以确认这是不可能的。