简体   繁体   中英

POST body not populating with PHP curl request set to application/json for TFS REST Endpoint

I'm struggling with a contradiction in expectations v. capabilities here, and hope that someone can help me out, or at least confirm that I'm not insane.

I'm attempting to build a two-way Slack integration with on on-premises Microsoft TFS REST endpoint, using Node.js and PHP as the main processors of the data to and from. I can successfully perform GETs against the on-prem TFS install using NTLM authentication, and parse the data through to Slack. So I know that (1) the endpoint is working, and (2) I am capable of authenticating to it.

However, in order to run a query against the TFS REST endpoint, you have to send a request that is content-type "application/json" or "application/json+patch". No matter what I do, using curl in PHP or natively in the Node.js application, I cannot get the query to be sent in the body of the request to the endpoint. Using another page to test this out, if I set the content-type to "multipart/form-data" or other standard types, I can send the body, but TFS will reject those requests as the wrong content-type.

Does anyone have any idea how to send a POST request that's both content-type "application/json" and will include the body using PHP or Node.js?

Here's the exact PHP that I've been using (which does not post a body, but does post data that can be read by PHP using file_get_contents('php://input')):

$ch = curl_init();
curl_setopt($ch, CURLINFO_HEADER_OUT, TRUE);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,TRUE);
curl_setopt($ch, CURLOPT_HEADER, TRUE);
curl_setopt($ch, CURLOPT_URL,$baseURL);    
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_NTLM);
curl_setopt($ch, CURLOPT_USERPWD, $userpwd);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postBody);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
    'Content-Type: application/json',
    'Transfer-Encoding: chunked',
    'x-metadata: testing',
    'x-testing: This is a value'
));
$result = curl_exec($ch);

And here's the error response from TFS:

"You must pass a query object in the body of the request."

If I change the remove the content-type header entirely, the body is sent (confirmed through another PHP page), but then I get this error from TFS:

"The request indicated a Content-Type of \\"application/x-www-form-urlencoded\\" for method type \\"POST\\" which is not supported. Valid content types for this method are: application/json, application/json-patch+json."

Update

So I can get a request to pass a body to an http endpoint by using a custom request, but when it attempts to connect to the https endpoint hosting the TFS instance, all the headers are getting dropped, which returns the last error above.

Headers sent to https:

'request_header' => string 'POST /tfs/{PROJECT}/_apis/wit/wiql?api-version=2.0 HTTP/1.1
Authorization: NTLM {TOKEN}

Headers sent to http:

'request_header' => string 'POST /dev/tfs/post.php HTTP/1.1
Host: {HOST}
Accept: */*
Transfer-Encoding: chunked
x-metadata: testing
x-testing: This is a value
Content-Type: application/json
40
' (length=203)

Here is the updated PHP:

$ch = curl_init();
curl_setopt($ch, CURLINFO_HEADER_OUT, TRUE);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
//    curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_RETURNTRANSFER,TRUE);
curl_setopt($ch, CURLOPT_HEADER, TRUE);
curl_setopt($ch, CURLOPT_URL,$baseURL);    
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_NTLM);
curl_setopt($ch, CURLOPT_USERPWD, $userpwd);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postBody);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
    'Content-Type: application/json',
    'Transfer-Encoding: chunked',
    'x-metadata: testing',
    'x-testing: This is a value'
));
$result = curl_exec($ch);

Update #2

Changing from "Content-Type:application/json" to "Accept:application/json" in the headers now makes the body post to the http endpoint, but the headers are still being dropped from the https endpoint.

Update #3 I can make successful requests to this endpoint using RESTlet within my Chrome browser, so it doesn't appear to be an issue with the TFS endpoint, but something in transfer between the PHP script and curl making the request.

You can capture the request and response headers by adding the following:

curl_setopt($ch, CURLOPT_ENCODING,"");
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($ch, CURLOPT_TIMEOUT,10);
curl_setopt($ch, CURLOPT_FAILONERROR,true);
curl_setopt($ch, CURLOPT_ENCODING,"");

curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_setopt($ch, CURLOPT_HEADER, true);

$data = curl_exec($ch);
if (curl_errno($ch)){
    echo 'Retreive Base Page Error: ' . curl_error($ch);
}
else {
  $info = rawurldecode(var_export(curl_getinfo($ch),true));
  $skip = intval(curl_getinfo($ch, CURLINFO_HEADER_SIZE)); 
  $responseHeader= substr($data,0,$skip);

echo "<pre>$info\n================\n$responseHeader\n===============\n";
echo substr($data,$skip);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM