Reputation: 1366
How to intercept a request and send it with HttpClient
to another server and return the response from that server after some modification?
The original request will contain data and files. I am looking for the least verbose solution, up to copying the original raw body as a string. The part I am stuck with is plugging the Request
object to the HttpClient
request in the shortest way (without writing code to copy data and headers bit by bit), the rest (handling the response) I will manage.
Upvotes: 4
Views: 3570
Reputation: 47329
Symfony's Http Client does not accept an HttpFoundation\Request
as a parameter to make new requests.
You'll need to convert the Request
object into the necessary parameters (including converting the path, method, passing appropriate headers, etc) "manually".
Then, you'd have to create the an HttpFoundation\Response
based on the client's response (which, again, cannot simply be sent back in your controller).
Depending on your specific requirements, it's not particularly onerous. A naive, probably buggy implementation would be something like:
use Symfony\Component\HttpFoundation;
use Symfony\Contracts\HttpClient\HttpClientInterface;
class FooProxy
{
public function __construct(private HttpClientInterface $client)
{
}
public function __invoke(HttpFoundation\Request $request): HttpFoundation\Response
{
$options = [];
$newServer = 'https://www.example.com';
$options['headers'] = $request->headers->all();
$options['body'] = $request->getContent();
$clientResponse = $this->client->request(
$request->getMethod(),
$newServer . $request->getRequestUri(),
$options
);
return new HttpFoundation\Response(
$clientResponse->getContent(false),
$clientResponse->getStatusCode(),
$clientResponse->getHeaders(false)
);
}
}
Again, this is very naive implementation. You'd need to make sure that you deal with any exceptions and edge cases. Use it as a starting point, and build according to your needs.
Take into account that PHP is not a great choice of language to build a real HTTP proxy.
Upvotes: 7
Reputation: 347
I did use the answer from @yivi.
But After a while I encounter the error mentioned by @Jacek Krysztofik.
After digging a while, I finnaly find the solution in the Symfony documentation.
Here is the corrected code:
use Symfony\Component\HttpFoundation;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Component\Mime\Part\Multipart\FormDataPart;
class FooProxy
{
public function __construct(private HttpClientInterface $client)
{
}
public function __invoke(HttpFoundation\Request $request): HttpFoundation\Response
{
$options = [];
$newServer = 'https://www.example.com';
$options['headers'] = $request->headers->all();
$options['body'] = $request->getContent();
if ($request->request->count()) {
// This is a post request, update the body and headers accordingly
$formData = new FormDataPart($request->request->all());
$options['headers'] = array_merge($options['headers'], $formData->getPreparedHeaders()->toArray());
$options['body'] = $formData->bodyToIterable();
}
$clientResponse = $this->client->request(
$request->getMethod(),
$newServer . $request->getRequestUri(),
$options
);
return new HttpFoundation\Response(
$clientResponse->getContent(false),
$clientResponse->getStatusCode(),
$clientResponse->getHeaders(false)
);
}
}
It's proabbly still not 100% bulletproof, but in my case it do the job for get and post requests.
Upvotes: -2