I was using the java.net.URL.openStream() method to retrieve content from the server. I recently ran into an issue where the HTTP Response code indicated an error, but instead of throwing an exception, the stream still was read anyway. This caused the error to appear much later in the execution and proved to be a red herring. As far as I can see, when you have opened a stream using this method, there is no way to check the HTTP response code.
The only way I could find to handle this properly was to obtain a connection before opening the stream:
HttpURLConnection conn=(HttpURLConnection) url.openConnection()
#Code updated with scotth's suggestion
if(!String.valueOf(conn.getResponseCode()).startsWith('2'))
throw new IOException("Incorrect response code "+conn.getResponseCode()+" Message: " +getResponseMessage());
rawIn=conn.getInputStream()
InputStream in=conn.getInputStream()
So do you agree? Are there any good circumstances for using openStream safely, or should its use be discouraged. It is worth noting that Sun uses the method in their tutorial code for reading directly from a URL. Then again, the code throws Exception so it isn't exactly a bastion of good coding practices.
openStream() works just fine if you want your class to be shielded from changes in the type of url - to change between, for example, absolute file paths (file:///), jar-contained resources, and potentially other protocols maybe even with custom protocol handlers (scotth://foo.bar).
However, as you've found its abstraction is quite high, so if you desire to know any details whatsoever about the nature of the interaction with the resource you'll need to openConnection() and cast as you see fit.
Re: other status codes - you probably want to glance at RFC2616 - if all you care about is "successful" you can just check that String.valueOf(conn.getResponseCode()).startsWith('2').
Related
First time using websockets. I have two machines that need to communicate using them. The server works fine, if I send a message with Postman, it replies correctly.
For the client I used one of the examples I found, like this. But in the client, when I create the WebsocketClientEndpoint :
final WebsocketClientEndpoint clientEndPoint =
new WebsocketClientEndpoint(new URI("ws://myserver.com/endpoint"));
it calls the onOpen and immediately after the onClose, returning a 1011 close reason, that I read is an unexpected condition in the server.
I would need some clue to analyse what can be happening, because as I said, the server replies well in Postman. The url is the same, of course. The examples I find are quite identical, and I am not doing anything different. Any idea?
My fault. As indicated by user207421, I should have checked what was really arriving to the server. The client was not sending hardcoded data. I was sending a JSON to it and it was forwarding it to the server. That server replied well to the same JSON if sent directly. The thing was that the client, in the deserialization and serialization, was sending the final reconstructed JSON with a missing field, and that made the server fail to reply. As dumb as that. The risk of assuming things.
First, I would recommend not to try to instantiate an instance of WebsocketClientEndpoint() as the only implementation of the class I can find uses static connect() methods, which require either an existing instance of WebSocketClient() or WebSocketContainer() - See this example. Instead, I would recommend creating a class that extends WebSocketClient and work with that instead - see an implementation of that here.
Also, another thing that might cause a different sort of problem is the possibility of an Unhandled Exception causing code execution to prematurely abort. The URI class throws a URISyntaxException, and if you are not wrapping your new URI object instantiation in a try/catch block or denoting the current scope method/class as throws URISyntaxException (or throws Exception to handle the other exceptions that might be thrown by WebsocketClient() as well) and have the thrown Exception(s) handled in a try/catch block in outer calling context, your code may be crashing due to that.
Normally I try to use exceptions only for "exceptional" conditions ("Effective Java ", Issue 69). My personal interpretation is:
if I hit a condition in a specific part in code (normally a method or constructor) where I can't give a meaningful answer or outcome anymore I throw an exception and whoever called the piece of code has to handle it.
In the special case of HTTP endpoints I can always give a meaningful answer - a response with a status code.
Handling bad requests thus belongs to normal program flow of endpoint methods and should not raise new exception.
E.g. an endpoint that returns a resource should just return 404 in case the resource is not found. In my opinion it would be bad practice to raise a "SomethingNotFoundExcetion" (that could be handled by an error handler and create 404 response)
My question is: It is bad practice to use Spring Boot's error handling mechanism for bad requests (4xy) that relies on exceptions to create specific HTTP responses. (It is really fine for all uncovered errors yielding 500)
(I am just writing a review of code and I am not sure if I should suggest to not use error handler for "normal" API interaction)
Answer/Comment to current answers
It seems that the most of you missed the important part of my reasoning:
(citing Effective Java, Item 69):
Use exceptions only for exceptional
conditions ...
this reasoning:
• Because exceptions are designed for exceptional circumstances, there is little
incentive for JVM implementors to make them as fast as explicit tests.
• Placing code inside a try-catch block inhibits certain optimizations that
JVM implementations might otherwise perform.
The main point for me is:
A well-designed API
must not force its clients to use exceptions for ordinary control flow.
Especially in case of rest API. It should be easy to use any API in a way to avoid exceptions at all. This means for me. No correct (defined e.g. in Open API) usage of a Rest API should raise an exception.
To put another point: The standard for SOAP (another http based API stuff) forbids to use "SOAP fault" for correct (defined by WSDL) requests.
For me raising exception in remote APIs on not exceptional cases are even worse then in classic API (via dependency).
It depends on your project, it's really a matter of opinion/architectural decision. I'd say either-or.
The advantage of using specific Exceptions and then using a Spring handler to map them is that it removes the tedious construction of responses with the correct code from the actual application logic code (it's not dissimilar from aspects in that respect): just throw the correct exception and be done with it.
OTOH, the distance to the error handling code means that 1. if something doesn't work, it may be difficult to track down the issue 2. you need to know what exceptions to throw, and that is not immediately obvious and needs to be documented well.
It is not a bad practice, but a matter of architectural decision. It could be good to have an error handler that will produce a 4xx response and will do some additional error handling work, such as logging, and/or sending a notification by mail or queue or (like in my project) write errors in the table so they could be reviewed by user using GUI component of an application and may be even edited and re-submitted if it makes sense. It also unifies the error handling to a single code (code re-use). But if you really just need to send a 4xx response and nothing else, then its OK not raise exception and just do it in your code. Raising exception is expensive performance-wise and shouldn't be done just for the sake of raising exception alone. But in this particular case my opinion is to use Exception/Spring boot Error handling mechanism
My problem is this, in Java, I have occasion to redirect a user elsewhere, where elsewhere is user definable. The code looks like:
response.sendRedirect(redirectURL).
My focus is on the string represented in the variable redirectURL.
My understanding is this, specifying response.setCharacterEncoding affects the content written to the response writer, not affecting the sendRedirect contents.
It would seem reasonable that by adding URIEncoding= on the connector, in tomcat based containers, should handle the case where the path of a URL is in, simplified Chinese, or Japanese, or non-ascii characters but it does not. Part of my question is why.
There have been many responses on here stating use URLEncode. However in issue 4571346
how to encode URL to avoid special characters in java
Wyzard states that shouldn't be used, rather
create a URI object
create proper URL string via toASCIIString.
In my for-instance use case, this works fine, albeit this code needs to be performed prior to every response.sendRedirect(), which are many.
As more and more applications have global use I see this issue effectively rendering insufficient the straight HTTPResponse method sendRedirect because, by itself, it may not work properly.
I refer all to RFC3490 which deals with Internationalized Domain Names in Applications, which discusses toASCII as one of two operations, the other being toUnicode.
Why, then, does URIEncoding= on the connector, not handle this, should it, and is there a more preferred way to deal with URLs where the path is internationalized?
I just believe, by way of separation of concern, this issue is and should be an container issue, not an application issue. My hope is this will provide a forum for discussion on this issue, not HTML, not forms, not anything other than the URL itself.
I have a code which does a POST to a URL. The code uses setFixedLengthStreamingMode since it knows the length of POST in advance.
I am having a situation where in some cases the URL could be redirected to something else and since streaming mode is enabled; its not able to follow redirect.
Is there any way to do a check before actually posting the data to see if URL is getting redirected or not? Or am I thinking in wrong direction?
In general, no, there isn't. In a normal web use case though after a POST request done from a submit form you should always get a redirect as per best practices, but this is far from guaranteed. For example, it can do a request if data is similar, and not do it if it is something else. It can always fail with an error.
For some limited use cases there might be some logic that is always followed, but that is case-by-case thing then.
From documentation:
When output streaming is enabled, authentication and redirection
cannot be handled automatically. A HttpRetryException will be thrown
when reading the response if authentication or redirection are
required. This exception can be queried for the details of the error.
So while the redirect will not be handled automatically, and even though you cannot really check for redirect beforehand, what you can do is that you can catch the exception and perform steps yourself based on that.
I have a a misbehaving calling application which I dont have the source for, which confronted with a non 200 http status- quietly logs an error/information message...
I need to be able to make it actually exit with some kind of error message. happen to know that it does catch some exceptions.... so this is my strategy
replace some part of the http client code with one that throws an exception and then let the exception bubble up to this app, where upon I expect it to exit...
Is there any other way/better to do this ? if not better simply suggestions of alternatives also welcome.
Thanks
That seems like a reasonable approach. You could also try using an aspect - if you use load-time weaving, you can add aspects to the client application at the point where you want it to throw an exception (though without the source code it will be tricky to work out the exact pointcut).