How to serve same response from HttpClient in my controller using Symfony? - symfony

I have a Controller that must forward the received request (changing some query parameters) to another server, and returns it's response (with same headers, status and body).
I decided to use HttpClient for doing that.
The problem is that HttpClient converts the content (i.e.: deflating gzip requests), and it breaks the output response.
Here is part of the example:
$response = $client->request($request->getMethod(), $extUrl, [
'headers' => $reqHeaders,
'timeout' => 45,
'verify_host' => false,
'verify_peer' => false,
'body' => $request->getContent(),
]);
#response data
$body = $response->getContent(false);
$statusCode = $response->getStatusCode();
$headers = $response->getHeaders(false);
return new Response($body, $statusCode, $headers);
Considering the second server returns a gzipped content, the response is broken, because it would keep the response header (content-type) but the $body will not be exactly the same, because HttpClient do me the favor of deflate the content.
The question is: is there a way to tell HttpClient to do not touch in my response body?
Or: is there a better way to make this "proxy" controller action?

I found that if accept-encoding is defined in the request headers, it's not inflated by CurlResponse class...
#\Symfony\Component\HttpClient\Response\ResponseTrait::$inflate
$this->inflate = !isset($options['normalized_headers']['accept-encoding']);
And
#\Symfony\Component\HttpClient\Response\response
$response->inflate = \extension_loaded('zlib') && $response->inflate && 'gzip' === ($response->headers['content-encoding'][0] ?? null) ? inflate_init(ZLIB_ENCODING_GZIP) : null;
So, I specified some empty encoding for those cases.
if (empty($request->headers->get('accept-encoding'))) {
//adding some accept-encoding will make httpclient response not to deflate the response (gzdecode) automatically
$request->headers->add(['accept-encoding'=> '']);
}
I still don't know if this is the best approach to forward a request and it's response in the controller, but the above solution solved my problem.

Related

How to sent a request by HTTP using relative url?

There's a HTTP Message like:
POST /v1.0/oauth2/accessToken HTTP/1.1
Host:api.dingtalk.com
Content-Type:application/json
{
...
}
If I want to send it by HTTP.post function, I should let url = "https://api.dingtalk.com/v1.0/oauth2/accessToken".
Could I use relative url url = "/v1.0/oauth2/accessToken", and write "host" => "api.dingtalk.com" in headers?
I know this is wrong way, I'm wondering how to separate them in two parts while using HTTP.request()?
I Tried:
url = "/v1.0/oauth2/accessToken"
headers = Dict([(
"host" => "api.dingtalk.com",
"Content-Type" => "application/json"
)])
body = Dict([
...
])
r = HTTP.post(url, headers, body)
get:
ERROR: ArgumentError: missing or unsupported scheme in URL (expected http(s) or ws(s)): v1.0/oauth2/accessToken
obviously it doesn't work.
With HTTP.request(), you can also use a relative URL and a Dict object for the headers as you've attempted, but you need to provide the full URL (including the protocol) as the base_uri argument, like this:
using HTTP
using JSON
base_uri = "https://api.dingtalk.com"
url = "/v1.0/oauth2/accessToken"'
full_url = base_uri * endpoint
headers = Dict([
"host" => "api.dingtalk.com",
"Content-Type" => "application/json"
])
body = Dict([
# your request body here
])
response = HTTP.request("POST", full_url, headers, JSON.json(body))
Hope this helps!

Computer Vision API - v1.0 Recognize Handwritten Text returns empty response

I am trying to start using the computer vision API but I keep getting an empty response. My request in php (as exported by Postman) looks like this:
<?php
$request = new HttpRequest();
$request->setUrl('https://westcentralus.api.cognitive.microsoft.com/vision/v1.0/recognizeText');
$request->setMethod(HTTP_METH_POST);
$request->setQueryData(array(
'language' => 'en',
'handwriting' => 'true'
));
$request->setHeaders(array(
'Postman-Token' => '442d04f7-49a0-4262-9d0f-666fe5240cc7',
'Cache-Control' => 'no-cache',
'Content-Type' => 'application/octet-stream',
'Ocp-Apim-Subscription-Key' => 'KEY'
));
try {
$response = $request->send();
echo $response->getBody();
} catch (HttpException $ex) {
echo $ex;
}
The above code works fine with the ocr endpoint!
The file is passed as binary using Postman.
Edit: I also tried to copy/paste the code from here: https://learn.microsoft.com/en-gb/azure/cognitive-services/computer-vision/quickstarts/php#ocr-php-example-request and if I change the ocr endpoint to recognizeText I get an empty response as well!
Unlike the other Computer Vision endpoints, RecognizeText is an asynchronous operation. Barring some issue with the image, you will get a 202 response instead of the usual 200 response. 202 responses customarily contain an empty response body. In this particular case you can find the URL where you can query for completion of the task. The documentation is here. The header you're looking for is Operation-Location.

How to access Response cookies in angular2?

I'm trying to access this cookies (the response ones):
When I open the request in the chrome debug tools in the network section I can clearly see that the cookies are present, but how can I access those values from my code? I've never worked with cookies before and I don't know what to do to "extract" them... I'm working on a Ionic2 project using Http.
I've read that the allowCredentials: true header has to be sent but that didn't work...
Here's the request/response details:
Here's the service:
public callLogin(service_guid: string, pos_guid: string, login_data: Object) {
return this.http.post(
this.url + service_guid + "/" + pos_guid + "/ack",
login_data,
{withCredentials: true}
)
.map(response => response.headers);
}
And the caller:
this.__posService.callLogin(login_data.service_guid, login_data.pos_guid, {"password": data.password})
.subscribe(
res => {
console.log("Success:");
console.log(res.get("apsession"); // this returns undefined
},
err => {
console.log("Error:");
}
);
When I try to access the cookie from the header it returns undefined. What am I doing wrong here?
The name of the response header you are trying to get is actually Set-Cookie not apsession. So if you did something like res.get("set-cookie") it would return the first header that matched that name. Since you have more than 1, you could do:
let headers: Headers = res.headers;
headers.getAll('set-cookie');
which returns a list of all headers with that name. You could find apsession in there probably.
See:
https://angular.io/docs/ts/latest/api/http/index/Headers-class.html
https://developer.mozilla.org/en-US/docs/Web/API/Response/headers
https://developer.mozilla.org/en-US/docs/Web/API/Headers

Is it possible to encapsulate request parameters in request object?

Is it possible to encapsulate request parameters in GuzzleHttp\Psr7\Request object?
I would like to pass around a completely configured request object with request parameters instead of passing them to Client::send() method along with the request.
$request = new Reques('POST', $url);
$client->send($request, ['form_params' => $parameters]);
I'd like to store the form_params in the request object. Is it possible?
Request class constructor doesn't receive an argument as a request sending parameters. You may only pass request headers:
public function __construct(
$method,
$uri,
array $headers = [],
$body = null,
$version = '1.1'
)
It doesn't provide any other methods to get and attach your POST parameters to the Request object either. So the answer is no, you can't store the form_params in the request object.

Angular2 : detect error from HTTP post

I cannot interecept error from http post
a part of my mservice (http post method)
addApplicationLink(applicationLink: ApplicationLink){
let body = JSON.stringify(applicationLink);
let requestHeaders = new Headers();
var headers = new Headers();
headers.set('Content-Type', ['application/json; charset=utf-8']);
let reqoptions = new RequestOptions({
headers: headers
});
return this._http.post(this._applicationLinksUrl + this._linkServicePath,body,{headers: headers});
in my component :
addApplicationLink() {
//todo
this.addNewLink = false;
/* check if must be done after call real rest service */
//this.applicationLinks.push(this.applicationLinkAdd);
this._applicationLinkService.addApplicationLink(this.applicationLinkAdd)
.subscribe(data => {
this.applicationLinks.push(this.applicationLinkAdd)
},
error => {
// handle error
console.error('this an erreor ' + error.status)
}
)
When user tries to add two same applicationlinks , the backend returns an error 409
But when I execute , error.status displays 200 in browser console
I see also in browser console
XMLHttpRequest cannot load http://localhost:7001...... No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 409.
rem : Http post is made with json , thus there is a prefligth call
Have you an idea to intercept error 409 ?
In fact, your server doesn't send back the CORS header (Access-Control-Allow-Origin' header is missing). This prevent the browser from providing the actual 409 error to the Angular2 application within the browser.
You need to fix first the problem on the server and you will be able to see this 409 error.
For more details about how CORS works, you could have a look at this article:
http://restlet.com/blog/2015/12/15/understanding-and-using-cors/

Resources