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.
Related
I'm new to Java and found a confusing behaviour related with RestTemplate.
It happened with an API returning large body (~5MB) over a quite slow network condition. The code is like below
ResponseEntity<MyEntity[]> result = restTemplate.exchange(url, HttpMethod.GET, entity, MyEntity[].class);
And also a ClientHttpRequestInterceptor is set to log before and after the request.
The confusing thing is that the after request log is logged only a while after remote server giving the response, and the HTTP Status code can be print in the log.
But the above statement took much more time to finally receive the data. Look inside the thread stack, it was reading data from socket.
I also look inside the resttemplate class and found:
response = request.execute();
handleResponse(url, method, response);
if (responseExtractor != null) {
return responseExtractor.extractData(response);
}
It seems to extractData after the execute().
My doubt is:
How does the client side know the status code even before get all the data? It just extracts necessary fields from the top packets?
Since the server has already sent out the response, where the response data is stored during the process?
It stores the data that it receives from the underlying HTTP in memory.
Client side can know what's the status code because with HTTP you get the headers and status code first before the response body. But this doesn't matter with RestTemplate as it promises to give you an object of ResponseEntity in the end, which contains everything from the http response be it status codex headers or body.
RestTemplate is an abstraction over an HttpClient, most client's give you the option to implement callbacks for separate events like onHeadersReceived(), onStatusReceived() etc. But if you are using RestTemplate this means you don't require such fine grained control.
Consider the following code.
try {
httpURLConnection = (HttpURLConnection) new URL(strings[0]).openConnection();
httpURLConnection.setConnectTimeout(Config.HTTP_CONNECTION_TIMEOUT);
httpURLConnection.setReadTimeout(Config.HTTP_CONNECTION_TIMEOUT);
httpURLConnection.connect();
responseCode = httpURLConnection.getResponseCode();
httpURLConnection.getHeaderFields();
}
finally {
httpURLConnection.disconnect();
}
The issue is even when I don't use the InputStream to read the response, in my Internet/Wifi connection logs I can see the response-body. What I want is simply to check a field in the header and based upon that field I will continue reading the InputStream.
My questions are these:
Is it correct behavior for the connected stream to automatically download all/partial file even before a BufferedInputStream is created and read from?
If yes, then is it possible to stop the file download until an InputStream is used to read the response?
If not then is there something I am doing wrong or missing?
The response includes both the header and the body, the server does not stop for the client to acknowledge the headers before sending the body.
At the time the client is able to read the response code from the headers, a part of the body has already been sent, the size of which depends on the network latency, buffering, ....
The current implementation of HttpURLConnection.getResponseCode() even use getInputStream() to ensure that the connection is in the correct state.
The client can choose to ignore the body, but it's usually not recommended, because it may prevent a persistent connection to be reused.
I am not sure about Android but since Java 6, a background thread is automatically used to read the remaining data.
If If-Modified-Since is not an option, why not use a HEAD request ? :
The HTTP HEAD method requests the headers that are returned if the
specified resource would be requested with an HTTP GET method. Such a
request can be done before deciding to download a large resource to
save bandwidth, for example.
I am using Java servlets using Apache tomcat.
I've configured a threadpool and am dealing with each request.
My page is taking in many GET requests at the same time, I'm wondering if I can respond to the server after each get request before any of the logic happens?
So server gives me a request -> I respond with either 'good send another' or 'bad send another' before I start my queueing.
Any help would be much appreciated!
EDIT
Sorry that was terribly written :(
What I'm asking for is a way to send a Header to the client (in this case it's a server which sends me lots of requests). The response would just be 200 or error based on the information I get sent.
What my program is doing:
My servlet gets sent lots of GET requests from one client. (over 100,000) Which I am using tomcat to queue and put into a threadpool. It is then assigned to a worker thread which processes it and puts it into a database.
I've been told to do is send a request back to that server saying 'ok received it'. I think I can use a header response but I don't have the URL of that client (and the client can change for different campaigns). So was wondering what the best way would be to send that response.
After doing some more research I think what I'm looking for is ServletOutputStream.
response.setContentType("text/html");
ServletOutputStream output = response.getOutputStream();
output.flush();
output.close();
Using servlet output stream where do I set the <head><body> tag? and insert the header response afterwards.
The simple answer is "sure".
If these are get requests from a web page for a web page, include a refresh timer and send back some token that can be used to identify the difference between a first-time-request and an I-requested-earlier-are-you-done request. In this case the refresh timer can be set via a meta refresh tag.
If the get requests are part of a REST API then you can define "got it and I'm working" into the protocol. For instance, return a 202 to indicate "got it but not done" and return 200 to indicate "done". As with the html page, consider sending some token back with the 202 that identifies the pending request.
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);
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.