PHP cURL POST returns a 415 - Unsupported Media Type
Solution 1
Problem solved! Here's the issue:
Sending an associative-array of headers DOES NOT WORK with cURL. There are several forums scattered around that show examples using an associative array for headers. DON'T DO IT!
The correct way (which is also scattered around the internets, but that I'm too dense to have noticed) is to construct your header key/value pairs as strings, and pass a standard array of these strings when setting the CURLOPT_HTTPHEADER option.
So in summary,
WRONG:
$headers = array( "Accept-Encoding" => "gzip",
"Content-Type" => "application/json",
"custom_header_1" => "test011",
"custom_header_2" => "test012",
"custom_header_3" => "test013");
RIGHT:
$headers = array( "Accept-Encoding: gzip",
"Content-Type: application/json",
"custom_header_1: test011",
"custom_header_2: test012",
"custom_header_3: test013");
I hope this comes in handy to some other noble doofus down the road before they waste as much time debugging as I did.
If I had to guess, I would assume that the same rule applies to the POST body key/value pairs as well, which is why @drew010 's comment about using http_build_query()
or json_encode()
to stringify your message body is a great idea as well.
Thanks to everyone for your very useful comments, and for you time and consideration. In the end, a side by side comparison of the http traffic (captured via Wireshark) revealed the issue.
Thanks!
Solution 2
I think the problem is that you are passing an array as the CURLOPT_POSTFIELDS
option. By passing an array, this forces the POST
request to use multipart/form-data
when the server is probably expecting application/x-www-form-urlencoded
.
Try changing
curl_setopt($request, CURLOPT_POSTFIELDS, $this->body);
to
curl_setopt($request, CURLOPT_POSTFIELDS, http_build_query($this->body));
See http_build_query for more information and also this answer: My cURL request confuses some servers?
Solution 3
This worked for me
$data ="data";
$headers = [
"Content-Type: application/json",
"X-Content-Type-Options:nosniff",
"Accept:application/json",
"Cache-Control:no-cache"
];
$auth = $USER . ":" . $PASSWORD;
$curl = curl_init();
curl_setopt($curl,CURLOPT_URL, $url);
curl_setopt($curl,CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl,CURLOPT_ENCODING, "");
curl_setopt($curl,CURLOPT_MAXREDIRS, 10);
curl_setopt($curl,CURLOPT_TIMEOUT, 0);
curl_setopt($curl,CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl,CURLOPT_HTTP_VERSION,CURL_HTTP_VERSION_1_1);
curl_setopt($curl,CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($curl,CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($curl, CURLOPT_USERPWD, $auth);
curl_setopt($curl,CURLOPT_HTTPHEADER, $headers);
$result = curl_exec($curl);
Solution 4
I had the same problem and I fixed changing the header.
My code:
$authorization = 'authorization: Bearer '.trim($apiKey);
$header = [
'Content-Type: application/json',
$authorization
];
curl_setopt($session, CURLOPT_HTTPHEADER, $header);
I don't know why the array function doesn't work :
curl_setopt($session, CURLOPT_HTTPHEADER, array('Content-Type:
application/json',
$authorization));
Ian
Updated on June 24, 2020Comments
-
Ian about 4 years
I've got a simple PHP script that sends an HTTP POST request via cURL, and expects a json string in response (would have loved to use an existing library like pecl_http/HTTPRequest for this, but can't). The call consistently fails with a 415 error - Unsupported Media Type. I think I'm not configuring cURL correctly, but after much searching, I can't find out what I'm doing wrong. Here's some code:
class URLRequest { public $url; public $headers; public $params; public $body; public $expectedFormat; public $method; public function URLRequest($aUrl, array $aHeaders, array $aParams, $aFormat = "json", $isPost = false, $aBody = "+") { $this->url = $aUrl; $this->headers = $aHeaders; $this->params = $aParams; $this->expectedFormat = $aFormat; $this->method = ($isPost ? "POST" : "GET"); $this->body = $aBody; } public function exec() { $queryStr = "?"; foreach($this->params as $key=>$val) $queryStr .= $key . "=" . $val . "&"; //trim the last '&' $queryStr = rtrim($queryStr, "&"); $url = $this->url . $queryStr; $request = curl_init(); curl_setopt($request, CURLOPT_URL, $url); curl_setopt($request, CURLOPT_HEADER, 1); curl_setopt($request, CURLOPT_HTTPHEADER, $this->headers); curl_setopt($request, CURLOPT_RETURNTRANSFER, 1); //curl_setopt($request, CURLOPT_SSL_VERIFYPEER, false); if($this->method == "POST") { curl_setopt($request, CURLOPT_POST, 1); curl_setopt($request, CURLOPT_POSTFIELDS, $this->body); //this prevents an additions code 100 from getting returned //found it in some forum - seems kind of hacky curl_setopt($request, CURLOPT_HTTPHEADER, array("Expect:")); } $response = curl_exec($request); curl_close($request); preg_match("%(?<=HTTP/[0-9]\.[0-9] )[0-9]+%", $response, $code); $resp = ""; if($this->expectedFormat == "json") { //parse response } elseif($this->expectedFormat == "xml") { //parse response } return $resp; } } $url = "http://mydomain.com/myrestcall"; $query = array( "arg_1" => "test001", "arg_2" => "test002", "arg_3" => "test003"); $headers = array( "Accept-Encoding" => "gzip", "Content-Type" => "application/json", "Accept" => "application/json", "custom_header_1" => "test011", "custom_header_2" => "test012", "custom_header_3" => "test013"); $body = array( "body_arg_1" => "test021", "body_arg_2" => array("test022", "test023"), "body_arg_3" => "test024"); $request = new URLRequest($url, $headers, $query, "json", true, $body); $response = $request->exec();
...and the response:
HTTP/1.1 415 Unsupported Media Type Server: Apache-Coyote/1.1 X-Powered-By: Servlet 2.5; JBoss-5.0/JBossWeb-2.1 Content-Type: text/html;charset=utf-8 Content-Length: 1047 Date: Mon, 18 Jun 2012 16:30:44 GMT <html><head><title>JBoss Web/2.1.3.GA - Error report</title></head><body><h1>HTTP Status 415 - </h1><p><b>type</b> Status report</p><p><b>message</b> <u></u></p><p><b>description</b> <u>The server refused this request because the request entity is in a format not supported by the requested resource for the requested method ().</u></p><h3>JBoss Web/2.1.3.GA</h3></body></html>
Any insights or ideas?
Thanks in advance!
-
Ian about 12 yearsThanks for the suggestion - same response though. I'll keep this in mind moving forward though. You make a good point.
-
drew010 about 12 yearsSniffing the entire request in Wireshark may be helpful so you can see the HTTP request and response. Are they expecting you to post JSON data rather than urlencoded data?
-
Ian about 12 yearsIt is expecting JSON, and per my response to Boris' comment, I'm going to follow your council, Wireshark my call along with the call sent from Poster, and compare the two.
-
drew010 about 12 yearsIn that case you may need to set
CURLOPT_POSTFIELDS
tojson_encode($this->body)
and confirm that the content-type header going out is not being overridden by curl back to anything other thanapplication/json
-
Ian about 12 yearsChecking out what wireshark has to say on the matter - thought I had it, and made this comment, then had to edit it to remove erroneous findings...
-
drew010 about 12 yearsCan you confirm that the
if ($this->method == 'POST')
block is being entered? Also, when you set theExpect
header in the post block, you are clearing all the headers that were previously set. Even so, I don't think that should revert the request back to GET though. -
Felipe N Moura over 5 yearsDamn! I was trying EVERYTHING and literally found dozens of different pages and tutorials showing how to set headers with key=>value and it simply wasn't working! THANKS, IAN!
-
Anjana Silva over 4 yearsThanks for saving possible hours/days of frustration mate :)