I have a server which expects Content-Length as a part of POST header. For POSTing, I am using Apache HttpComponents library.
This is a stripped down version of the expected request (with all the required headers ofcourse):
POST /ParlayREST/1.0/sample/ HTTP/1.1
Content-Type: application/json
Accept: application/json
Host: server.url.com:8080
Content-Length: 287
{
"listenerURL":"http://application.example.com/notifyURL"},
"sessionId":"12345"
}
I have used the setEntity method of HttpPost to set a StringEntity (converted json -> String -> StringEntity) as content of the POST. But when I execute the request, I end up with a POST request which doesn't specify Content-length within it's header.
Is there anyway to add this missing header?
(I tried setHeader() to set the Content-Length which threw an error saying that the content length is already present)
This is the code that I am using to create the POST request:
//Convert the registration request object to json
StringEntity registrationRequest_json_entity = new StringEntity(gsonHandle.toJson(registrationRequest));
registrationRequest_json_entity.setContentType("application/json");
//Creating the HttpPost object which contains the endpoint URI
HttpPost httpPost = new HttpPost(Constants.CLIENT_REGISTRATION_URL);
httpPost.setHeader(HTTP.CONTENT_TYPE,"application/json");
httpPost.setHeader("Accept","application/json");
httpPost.setHeader(HTTP.TARGET_HOST,Constants.REGISTRATION_HOST + ":" + Constants.REGISTRATION_PORT);
//Set the content as enitity within the HttpPost object
httpPost.setEntity(registrationRequest_json_entity);
HttpResponse response = httpClient.execute(httpPost, new BasicHttpContext());
HttpEntity entity = response.getEntity();
if (entity != null) {
//work on the response
}
EntityUtils.consume(entity);
HttpClient automatically generates Content-Length and Transfer-Encoding header values based on properties of the enclosed message entity and the actual protocol settings.
Do not set those headers manually.
Try:
httppost.setHeader(HTTP.CONTENT_LEN,"0");
This will set the content length to 0.
Related
I am trying to use a web API in a Java program using Apache HttpClient5.
Using a simple request with curl:
curl -X POST -H "x-api-user: d904bd62-da08-416b-a816-ba797c9ee265" -H "x-api-key: xxxxxxxxxxx" https://habitica.com/api/v3/user/class/cast/valorousPresence
I get the expected response and effect.
Using my Java code:
URI uri = new URIBuilder()
.setScheme("https")
.setHost("habitica.com")
.setPath("/api/v3/user/class/cast/valorousPresence")
.build();
Logger logger = LoggerFactory.getLogger(MyClass.class);
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
HttpPost httpPost = new HttpPost(uri);
httpPost.addHeader(new BasicHeader("x-api-user",getApiUser()));
httpPost.addHeader(new BasicHeader("x-api-key", getApiKey()));
CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
logger.info(httpResponse.toString());
return httpResponse.getCode();
The output I get when running the Java call is
411 Length Required HTTP/1.0
I'm sure I'm not constructing the POST call correctly, how should it be done? I've tried specifying Content-Type and that has no effect. Trying to set Content-Length in the code causes compilation errors (as I understand it, this is handled behind the scenes by HttpClient5).
All my GET requests using HttpClient5 work fine.
A POST always has a payload (content). A POST without content is unusual, so are you sure you didn't forget something?
You need to call setEntity() to set the payload, even if it is empty, because it is the entity that sets the Content-Length header.
E.g. you could call httpPost.setEntity(new StringEntity("")), which sets Content-Type: text/plain and Content-Length: 0.
I am trying to POST a request using JAVA HTTPCLIENT, and while doing so, I am getting 404 Bad Request.
I tried writing the JAVA code in Eclipse and got 404 Bad Request and tried sending the request through POSTMAN and received HTTP Status 500
package com.apex.customer.service;
public class CustServicePostTest {
public static void main(String[] args) throws ClientProtocolException, IOException {
String url = "http://www.thomas-bayer.com/sqlrest/CUSTOMER/102";
//create the http client
HttpClient client = HttpClientBuilder.create().build();
//create the post message
HttpPost post = new HttpPost(url);
List<NameValuePair> urlParameters = new ArrayList<NameValuePair>();
urlParameters.add(new BasicNameValuePair("ID", "102"));
urlParameters.add(new BasicNameValuePair("FIRSTNAME", "Apex"));
urlParameters.add(new BasicNameValuePair("LASTNAME", "Consultancy"));
urlParameters.add(new BasicNameValuePair("STREET", "Shell Blvd"));
urlParameters.add(new BasicNameValuePair("CITY", "Fremont"));
post.setEntity(new UrlEncodedFormEntity(urlParameters));
HttpResponse response = client.execute(post);
System.out.println(response.getStatusLine().getStatusCode());
System.out.println("Parameters : " + urlParameters);
System.out.println("Response Code: " + response);
System.out.println(response.getStatusLine().getReasonPhrase());
}
}
I am looking for 200 OK request.
The issue here is due few mistakes:
First is related to the input format. The code you're using tries to map key and values, but as I could see from this guide, it expects a XML format in a plain text as input.
The second mistake is that you are trying to post over an existing ID. In this case, to create a resource you should use http://www.thomas-bayer.com/sqlrest/CUSTOMER/
So in this case in order to make it work, try something like this:
String url = "http://www.thomas-bayer.com/sqlrest/CUSTOMER/";
HttpClient client = HttpClientBuilder.create().build();
HttpPost post = new HttpPost(url);
String xml = "<resource>";
xml += "<ID>102</ID>";
xml += "<FIRSTNAME>Apex</FIRSTNAME>";
xml += "<LASTNAME>Consultancy</LASTNAME>";
xml += "<STREET>Shell Blvd</STREET>";
xml += "<CITY>Fremont</CITY>";
xml += "</resource>";
post.setEntity(new StringEntity(xml));
HttpResponse response = client.execute(post);
System.out.println(response.getStatusLine().getStatusCode());
System.out.println("Response Code: " + response);
System.out.println(response.getStatusLine().getReasonPhrase());
It is also very useful to learn another way to test it with tools like curl command line utility. For example you can POST a product like this:
curl -X POST http://www.thomas-bayer.com/sqlrest/PRODUCT/ -d '<resource><ID>103</ID><NAME>X</NAME><PRICE>2.2</PRICE></resource>'
Once you solve this, it will be important to get used with HTTP codes. For example a 500 error means something wrong on the server side while a 404 usually means that you're hitting an invalid endpoint (it does not exists).
Finally, I'll not discuss why are you using this project to send HTTP requests to a server - but keep in mind that this is not a very common way to go. Currently the REST with JSON would be much more interesting and enjoyable :) In case you're interested on it, take a look on Spring Boot REST
I've got a small piece of code which submits an XML entity along with binary data in the same POST. I'm using the httpclient and httpmime for this.
I'm not quite sure if I should set the Content-Type header for this request. After all, the Content-Type is both application/xml and application/octet-stream.
What's the correct usage for this?
post = new HttpPost(uri);
post.setHeader("Authorization", auth);
// Should I set Content-Type at all?
post.setHeader("Content-Type", mimeType + ";charset=UTF-8");
MultipartEntityBuilder b = MultipartEntityBuilder.create();
b.addTextBody("data", payload, ContentType.APPLICATION_XML);
b.addBinaryBody("file", file);
post.setEntity(b.build());
No, you should not. You should let HttpClient generate Content-Type as well as other content metadata headers automatically based on properties of the message entity.
I have a simple method to send a POST request:
public HttpResponse post(InputStream content, String contentType, URI url) {
InputStreamEntity entity = new InputStreamEntity(content);
entity.setChunked(true);
entity.setContentType(contentType);
HttpPost httpPost = new HttpPost(url);
httpPost.setEntity(entity)
return httpClient.execute(httpPost, httpContext);
}
The httpPost seems well configured:
httpPost.getEntity().toString() = [Content-Type: application/json,Chunked: true]
httpPost.getEntity().getContentLength() = -1
But the remote server receives Content-Length header
A request on http://httpbin.org/post shows the actual headers are:
"headers":{
"Accept-Encoding": "gzip,deflate",
"Content-Length": "571",
"Content-Type": "application/json",
"Host": "httpbin.org",
"User-Agent": "blabla",
"Via": "1.1 localhost (Apache-HttpClient/4.5.2 (cache))"
}
=> Does org.apache.http.client 4.5 really support chunked-encoding or does it fake it ?
Thank you
Chunked data is definitely supported by Apache HttpClient.
Httpbin.org relies on Nginx and I guess buffering of proxy's requests is enabled in their configuration. Consequently, you do not see chunked transfer encoding in the result returned by httpbin.
Instead of using an external service such as httpbin.org for checking this kind of headers, use your own webserver.
I am using Apache HTTP Client Library to send HTTP request. I have following questions:
1- Does this library attaches any default headers to the request, or you have to attach all the headers yourself.
HttpClient client = new HttpClient();;
HttGet request = new HttpGet('http://www.example.com');
//Now Can i execute the request directly or do i need to
//add headers before executing the request
client.execute(request);
2- I also want to see the headers that are being sent to the server. I tried "request.getHeaders()" but it just prints - "[Lorg.apache.http.Header;#1bc2616". How can I get it to print headers in a name - value format.
What version of Apache HttpClient are you using? In version 4.0.1 there is a method HttpGet#getAllHeaders() which returns an array of Header object. See grep code here - http://grepcode.com/file/repo1.maven.org/maven2/org.apache.httpcomponents/httpcore/4.0.1/org/apache/http/message/AbstractHttpMessage.java#AbstractHttpMessage.getAllHeaders%28%29
I tried running this code:
final HttpClient client = new DefaultHttpClient();
final HttpGet get = new HttpGet("http://www.google.com");
client.execute(get);
for (final Header header : get.getAllHeaders()) {
System.out.println("Header: " + header.getName() + " = " + header.getValue());
}
System.out.println(get.getAllHeaders().length);
I did not see any headers getting printed in the console and get.getAllHeaders().length returned zero (0). So I would assume that HttpClient doesn't provide any default Headers.
I wouldn't recommend to use separate HttpGet/HttpPost/HttpPut
but HttpRequest Interface. There you'll be able to set Header/body as HttpEntity.
But Default header is attached:
method: GET/POST/PUT by default;
You should separately set Content-Type and Encoding