java.net.http.HttpClient POST request sends empty body - java

Java (tested on JDK11 and JDK17) HttpClient POST request with a "hello" body delivers empty body to the server.
val response = java.net.http.HttpClient.newHttpClient()
.send(
java.net.http.HttpRequest.newBuilder()
.uri(URI.create("http://...."))
.POST(java.net.http.HttpRequest.BodyPublishers.ofString("hello", StandardCharsets.UTF_8))
.build(),
java.net.http.HttpResponse.BodyHandlers.ofString());
No exception throw, response.statusCode() is 202, the content-length header shows 5, but the request body is empty. Tested against multiple server implementations and Postman mock server.
I am executing this code from within a JUnit test.
OpenJDK 64-Bit Server VM Temurin-17.0.5+8 (build 17.0.5+8, mixed mode, sharing)
Update 2023-02-05
Debugging into the JVM, I see two buffers are queued for posting. One contains 9 characters (encoded message start frame?) and the second contains my 5 characters 104, 101, 108, 108, 111 (i.e. hello).
The body publisher then seems to only send the first 9 characters and never my actual 5 character payload. Log follows (please pardon the length):
Full java.net.http log file

Per #tevemadar's suggestion, setting a content type (Postman) makes the HttpClient push the data, (or the server to pull the data).
Adding .header("Content-Type", "text/plain") helped made the body appear on the other side. Full code:
var response =
java.net.http.HttpClient.newHttpClient()
.send(
java.net.http.HttpRequest.newBuilder()
.uri(URI.create(uri))
.header("Content-Type", "text/plain")
.POST(
java.net.http.HttpRequest.BodyPublishers.ofString(
"hello", StandardCharsets.UTF_8))
.build(),
java.net.http.HttpResponse.BodyHandlers.ofString());
Not setting any content-type on the HttpRequest makes the HttpClient::send method call (or the server-side) ignore the request body (or perceive it as an empty body). There is no error, no warning, nothing in the JDK debug logs.
Setting any (even wrong) content type makes the body come across to the server side.

Related

HTTP Error 411 for startOptimization request of routeoptimization api

I'm trying to send a startOptimization request to https://api.myptv.com/routeoptimization. I generated my java client as described in the tutorial: https://developer.myptv.com/Tutorials/General/clientGeneration.htm
Creating a plan works but when I want to optimize it I get the following error:
HTTP Error 411. The request must be chunked or have a content length.
I noticed that this error is also returned when I send a startEvaluation request. All other requests of the route optimization api and all other APIs seems to work.
Unfortunately this is a bug in the API Managment of Microsoft. We created a ticket for Microsoft but we don't know when it is fixed.
The problem is that the API Managment rejects POST requests with an empty body where no Content-Length header of 0 is passed. The java client does not pass this header for an empty body, therefore either the empty body must be avoided or the header must be added until the bug is fixed.
There are two possible solution to solve this problem:
Just pass a dummy body which is ignored anyway. For this you have to adapt the java client after generation:
replace all occurencies of
localVarRequestBuilder.method("POST", HttpRequest.BodyPublishers.noBody());
with
try {
byte[] localVarPostBody = memberVarObjectMapper.writeValueAsBytes("dummybody");
localVarRequestBuilder.method("POST", HttpRequest.BodyPublishers.ofByteArray(localVarPostBody));
} catch (IOException e) {
throw new ApiException(e);
}
Explicitly send a Content-Length header of 0 by adding
System.setProperty("jdk.httpclient.allowRestrictedHeaders", "Content-Length");
to a setup method of your main and adding
localVarRequestBuilder.header("Content-Length", "0");
to the startEvaluationRequestBuilder and startOptimizationRequestBuilder methods.

Client gets empty response after setting status to HttpServletResponse

In a java web-app I write to my HttpServletResponse:
httpResponse.getWriter().write(someJsonString);
httpResponse.getWriter().flush();
The client (apache jmeter in this case) gets the response with the json in the body and status 200 as expected.
If I decide to change the response status:
httpResponse.getWriter().write(someJsonString);
httpResponse.setStatus(Response.Status.NO_CONTENT.getStatusCode());
httpResponse.getWriter().flush();
My client gets the response with the right status (204 in this case) but an empty body for some reason.
What can cause this?
When you send response as 204, it means there is no body.
See w3c rfc
The 204 response MUST NOT include a message-body, and thus is always terminated by the first empty line after the header fields.
It means while sending response either container is not considering body or your client is discarding after reading status in response.
One way could be to check this response in web-browser if possible. With tools like fire-bug or similar in Chrome you could actual check response.

Jersey client.setChunkedEncodingSize(null) not working

I am writing one client to measure Jersey, REST based web service performance. I have written some code to measure response time and to measure number of bytes sent from the server but response.getLength() method always returning -1.
In many QA forum I read that setting client.setChunkedEncodingSize(null) will work but even after setting this, I am getting -1.
From server side, I am sending response of type XML or JSON or protobuf depending upon parameters sent by client. For all of these response types, I am getting response length as -1.
My actual request looks like below:
WebResource webResourceQuery = client.resource(requestUrl);
ClientResponse response = webResourceQuery.header("Authorization", header)
.accept(MediaType.APPLICATION_JSON)
.get(ClientResponse.class);
From server side, I am not setting content-length explicitly. Can anyone please help me in getting content-length on client side?
Whole purpose of this experiment is to measure which response type is more efficient in terms of response time and amount of data sent/received.
I ran in to the same problem: client.setChunkedEncodingSize(null); does not work.
This worked for me to actually disable chunked encoding:
client.getProperties().put(ApacheHttpClient4Config.PROPERTY_ENABLE_BUFFERING, true);

Does the server send response only when its HTTP 200?

im writing a java application that sends a post request to a server and expect a json from the server. Now when i need to get the response from the server do i only need to get it from the inputStream when the http code is 200 (HTTP OK) or is there any other cases ? , example :
//...
if (urlConn.getResponseCode() == HttpURLConnection.HTTP_OK) {
// only here try to get the response
}
//...
It depends on how the server is implemented. Check the API, if the server has one. If it's internal, ask your server guy.
Generally speaking, if your response code is either 2xx or 3xx, I would check the response anyway...
If the server your communicating with is following the spec then either 200 or 201 responses are valid to contain an entity. A 204 response is successful but has no data in the response.
See section 9.5 here: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5 for details of acceptable responses to a POST. Extract below:
The action performed by the POST method might not result in a resource
that can be identified by a URI. In this case, either 200 (OK) or 204
(No Content) is the appropriate response status, depending on whether
or not the response includes an entity that describes the result.
If a resource has been created on the origin server, the response
SHOULD be 201 (Created) and contain an entity which describes the
status of the request and refers to the new resource, and a Location
header (see section 14.30).
There are three things to consider:
All 2xx codes denote success of some sort. But depending on the exact code, your reading code might be different. (204 for example means success but no content.)
There are redirecting codes (3xx). These are usually automatically followed by the http client library but you can also set them not to, in which case you need to have custom code that handles these cases.
There can be valuable information returned in the stream even if you get a code that denotes an error. Whether you want to process it depends on your exact needs.

Sending an error response with com.sun.net.httpserver.HttpServer

I'm an experienced Java programmer but a newbie web developer. I'm trying to put together a simple web service using the HttpServer class that ships with JDK 1.6. From the examples I've viewed, some typical code from an HttpHandler's handle method would look something like this:
Headers responseHeaders = exchange.getResponseHeaders();
responseHeaders.set("Content-Type", "text/plain");
exchange.sendResponseHeaders(200, 0);
OutputStream responseBody = exchange.getResponseBody();
responseBody.write(createMyResponseAsBytes());
responseBody.close();
My question: What happens if I send a response header to indicate success (i.e. response code 200) and perhaps begin to stream back data and then encounter an exception, which would necessitate sending an "internal server error" response code along with some error content? In other words, what action should I take given that I've already sent a partial "success" response back to the client at the point where I encounter the exception?
200 is not sent until you either flush the stream or close it.
But once it is sent, there is nothing you can do about it.
Usually it may happen only when you have a really large amount of data and you use chunking.

Categories

Resources