I have a problem when I am trying to POST data to third party API. I'm getting an error
yii\base\ErrorException: Header may not contain more than a single header, new line detected in /www/wwwroot/xxx/vendor/yiisoft/yii2/web/Response.php:382
As far as I know yii manages headers by itself and I added additional headers for auth purposes.
My additional headers:
protected function getHeaders($data = [])
{
ksort($data);
reset($data);
$ts = microtime().rand(0, 10000);
return [
'login: '.$this->login,
'ts: '.$ts,
'sig: '.md5($ts.$this->apiKey),
];
}
Code works in pure php tests, but not inside yii app.
I already tried to log response and request headers, didn't find any duplicated headers.
Only something like this one:
'CONTENT_TYPE' => 'application/json; charset=utf-8'
But I don't know if this counts for multiple headers.
The problem was on the API provider's side. My requests were not passing authentication, and I was getting back gibberish with incorrect headers.
Related
I'm trying to create a "service" like application, which can be able to receive API calls from another services. (These services will be built, for different purposes). And also able to send API calls to an another one.
Each request that they send, and accept has to have the following format.
{
header : {
// some header information, like locale, currency code etc.
signature : "some-hashed-data-using-the-whole-request"
},
request : {
// the usable business data
}
}
To each request I want to append a hash, that is generated from the actual request or anyhow (salted with password or any kind of magic added). Its not that important at the moment. I gave the name signature to this field. So for each received request, I want to reproduce this signature from the request. If the signature I received is matching with the one I generated, I let the application run otherwise showing some error message.
I already read a few articles, but most of them is for user-pass combinations.
My question is not about that if it's a good solution or not. I just want to know how can implement a middleware like functionality - like in laravel - in Symfony 4?
Instead of putting headers into a JSON object the HTTP body, use HTTP headers directly. That’s what they are for. When you’re using non-standard headers, prefix them with X- and maybe a prefix for your application, for example X-YourApp-Signature. The request goes into the body, i.e. the value of the request property in your example.
The server side is pretty simple with Symfony:
public function someAction(Request $request)
{
$signature = $request->headers->get("X-YourApp-Signature");
$data = json_decode($request->getContent());
// ... go on processing the received values (validation etc.)
}
If you want to write a HTTP client application in PHP, I would recommend using the Guzzle library. Here’s an example:
$headers = ["X-YourApp-Signature" => "your_signature_string"];
$data = json_encode(["foo" => "bar"]);
$request = new \GuzzleHttp\Psr7\Request("POST", "https://example.com", $headers, $data);
$client = new \GuzzleHttp\Client();
$response = $client->send($request, ["timeout" => 10]);
var_dump($response);
Of course, you’ll also want to implement some error handling etc. (HTTP status >= 400), so the code will be a bit more complex in a real application.
As k0pernikus mentioned, the before after filters solves my issue.
I'm building an api at my company using laravel.
The problem I'm encountering is that if you send an api request without defining the correct header with the request you will get html back if there is a failure e.g. authorization failure or findOrFail() failure.
My thinking is that you never want to return html (even if the user has the wrong header).
I have a couple of solutions. In BeforeMiddleware.php I can manually insert a header into the request such as:
// Check if we are on an api route
$apiRoute = strncmp($uri, '/api/', 5) == 0;
// Insert the request header to force json response
if ($apiRoute){
$language = $request->header->add('Accept', 'application/json');
}
The 2nd solutions would be to throw an error if they don't have the correct header.
What would be the best way to enforce a json response, what is a good practice for handling api responses in laravel?
Once you detected that you are on your api path you are out of the woods and can indeed tackle your problem in the app\Exceptions\Handler.php file like suggested on How do you force a JSON response on every response in Laravel?.
For an open source project I created JSON exception objects by Microsoft format as output, but you can choose the jsonapi format (http://jsonapi.org/examples/#error-objects-basics) as you like:
https://github.com/StadGent/laravel_site_opening-hours/blob/develop/app/Exceptions/Handler.php
(note that on this implementation it is indeed depending from the headers, but you can use your path detection I think)
I'm developing a REST-based web API with Yii2. Through testing, it seems that, in order to be successful, POST requests to the API need to have the Content-Type HTTP header set. (One tester was using Postman without setting the Content-Type header and was receiving 500 error responses in return, while another tester was using cURL and setting the Content-Type header and was receiving 200 success responses. When the Content-Type header is omitted, the POST data seems to be stripped from the request somewhere along the line, and no POST data gets logged by Yii for these requests.)
I was mostly following Yii's own guide for development and wasn't aware of any requirements in this area. Could someone explain why the Content-Type header must be set and what is happening otherwise?
I have discovered by looking in the Yii source code that there is a workaround.
When retrieving parameters that are submitted via POST (or other request methods) by calling the yii\web\Request::getBodyParam() method, the method checks if there is a parser set for the Content-Type of the request, but the method also checks if there is a parser set for Content-Type '*' (elseif (isset($this->parsers['*']))). So in my Yii application configuration, I just need to set the JsonParser for '*'...
'parsers' => [
'application/json' => 'yii\web\JsonParser',
'*' => 'yii\web\JsonParser'
]
and then I don't need to rely on clients having the Content-Type HTTP header set (as long as I handle the POST data sensibly).
I am working on proxy with PHP. In my php code I am sending proper required headers and expected to get response body and headers. However I am getting response body correctly as I want but not getting headers properly (supposed to get Status 200 but getting 401). When i traced with firefox I found that SAP URL itsself making 2 request internally by using data which I send. so with my first request it is not authenticated so SAP url itslef managining to send same request again and 2nd time it gives both proper response body with headers. Howevber I php code when I get it i get response body from 2nd response and headers from 1st response.
here is code.
$opts = array(
'http'=>array(
'method'=>"POST",
'content' => $xml_request,
'header'=>array("Host:" . $sap_url,
"Content-Type: text/xml; charset=UTF-8",
$authstring,$xml_request)
)
);
$context = stream_context_create($opts);
$result = file_get_contents($sap_url, false, $context);
$http_res_array = get_headers($sap_url);
You should probably use curl functions instead and do BOTH requests yourself. file_get_contents, does the second request for you, but takes away the possibility to fetch the second headers.
Maybe a little old but anyways:
You're using the get_headers()-function to get the headers. It's documentation states that:
Fetches all the headers sent by the server in response to a [new] HTTP request
It doesn't empathize that this function will actually send a new request to the server and return the response-header for that request. Therefor, the headers can be slightly different.
Since you're using file_get_contents() to load the content, you can use the global $http_response_header-variable right after your request, which will contain the response-header from the last executed request.
In my controller action, I have this:
$pdf = $this->Invoice->makePdf($invoice);
$this->response->charset('UTF-8');
$this->response->body($pdf);
$this->response->type(array('pdf' => 'application/x-pdf'));
$this->response->disableCache();
$this->response->send();
However, no matter what I do, CakePHP always sends the data as text/html; charset=utf-8. I have also tried
$this->response->header(array('Content-Type' => 'application/x-pdf'));
But it still sent it as text/html. How can I force the response to be sent using the content type above?
Doing $this->response->type(array('pdf' => 'application/x-pdf')); stores/replaces the content type for the associated key as mentioned in the api. Use $this->response->type('pdf'); to set the type.
Edit: Also don't call $this->response->send(); just return the response object return $this->response; and let the dispatcher handle the sending.