I have a scenario in Spring MVC , where I have to throw an Exception explicitly in the handleRequest Method.
For Eg.
public class AdminController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
// for some request parameter this is run. For Eg. reqParam=xyz
undeployTables();
}
public void undeployTables() throws Exception {
throw new Exception("Undeploy Exception");
}
Now assuming that spring servlet and url mapping is configured in web.xml, when i try to access the servlet via url http://localhost:8080/server/admin?reqParam=xyz, I get an correct error on page. java.lang.Exception: Undeploy failed....
But when I try to access the code via HTTPClient, that is via the java code the response in the client is not able to catch this exception and only I get is the HTTP 401 Internal Error as response object.But what i would Like to have is an Exception object in client.
Code is :
HttpPost httppost = new HttpPost(url.toURI());
httpclient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, timeout);
logger.info("executing request " + httppost.getURI()); //$NON-NLS-1$
// Create a response handler
HttpResponse response = httpclient.execute(httppost);// expect exception to be thrown here
statusCode = response.getStatusLine().getStatusCode();
Can you please let me know where the changes should be done so that the exception on the Client could be caught.
I could google but couldnt find a appropriate answer.
Exceptions can't be thrown over HTTP. What you'll need to do is:
On the server side, handle the exception and make sure your HTTP response has an appropriate statusCode and/or response header/body.
On the client side, translate that response into the exception you want.
You should investigate what interfaces HttpClient provides for exception handling.
My answer to this question might help you with the server side:
https://stackoverflow.com/a/11535691/1506440
Related
I have a Spring application (not using Spring boot) deployed to tomcat
I'm trying to return error 401 (HttpServletResponse.SC_UNAUTHORIZED) on specific URLs in given condition using OncePerRequestFilter ,
But I keep getting Not found error:
Response code: 404
My Filter(removed conditions):
#Component
public class MyFilter extends OncePerRequestFilter {
private static final Logger logger = Logger.getLogger(MyFilter.class);
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Not autorized");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
try {
PrintWriter out = response.getWriter();
out.write(""); // Empty
out.flush();
} catch (IOException e) {
logger.error("error filtering", e);
}
return; // stop chain
}
}
I tried using similar code to previous similar answer
I believe you can response.sendError inside do Filter method.
EDIT
If I just throw an exception instead I get a generic error code 500
Response code: 500
EDIT 2
I'm adding filter inside onStartup method overriden WebApplicationInitializer's
FilterRegistration myFilter = servletContext.addFilter("myFilter ", MyFilter.class);
myFilter.addMappingForUrlPatterns(null, false, "/myservlet/myendpoint/*");
EDIT 3
Also my filter in #Componenet and its package include in component scan
#ComponentScan(basePackages = { "my.parent.pacakge"})
I tried your code and it works. Different error codes were getting successfully returned. Although, I wanna point out a couple of things-
The method sendError() sends the response to the client and also clears the response buffer. So, anything you write after it into the response after that is of no use.
Calling setStatus() is of no use either. The HTTP response and HTTP response code has already been sent to the client in the above line when you called sendError().
Now, this is my hypothesis why your code is not working for you, but it is for me-
The reason that you might be getting HTTP 404 is that your API is not present. This can be due to a spelling error or maybe due to a simple ignorance like calling your API named /foo/bar like /foo/bar/ i.e. with extra trailing forward slash. I believe that your filter is getting executed successfully and you must be doing something useful there, not the sample code of sendError() that you have explained in the question.
Also, when you throw an Exception in your filter, the control does not reach to the API and API lookup does not happen. Hence, the default HTTP 500 response is sent to the client due to the unhandled exception instead of HTTP 404.
It return 401 as expected only if setStatus is executed after out.write
PrintWriter out = response.getWriter();
out.write("");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
when i use below code , what is the case to get HttpStatusCodeException exception .
ResponseEntity<Object> response =
restTemplate.exchange(builder.build().encode().toUri(), HttpMethod.GET, entity, Object.class);
Please can anyone help out ????????
According to documentation there are two types of HttpStatusCodeException HttpClientErrorException and HttpServerErrorException.
The former is thrown when an HTTP 4xx is received.
The latter is thrown when an HTTP 5xx is received.
so you can just use ResponseEntity.BodyBuilder.status(505) for example to raise an HttpServerErrorException in your
exhange(...) method of org.springframework.web.client.RestTemplate class was added in 3.1.0.RELEASE of spring-web library.
This method throws RestClientException which covers client (4_xx) and server (5_xx) side http code errors. But RestClientException doesn't offer getStatusCode(), getResponseAsString(), etc... methods.
HttpsStatusCodeException is the child of RestClientException which is doing same thing but with additional methods like getStatusCode(), getResponseAsString(), etc.
HttpClientErrorException child of HttpsStatusCodeException and only entertain client error (4_xx) not the server error.
HttpServerErrorException child of HttpsStatusCodeException and only entertain server error (5_xx) not the client error.
HTTP Status Codes are responses from the server, therefore if you have control of the server then you could make it return whichever errors you want. If you don't have control of the server then you could try sending bad/invalid requests so that the server will complain.
Something like this on your server side:
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity getAnError() {
// complain!
return ResponseEntity.status(HttpStatus.FORBIDDEN);
}
I have a RESTful resource, which calls a EJB to make a query. If there is no result from the query, the EJB throws a EntityNotFoundException. In the catch block, it will be thrown a javax.xml.ws.http.HTTPException with code 404.
#Stateless
#Path("naturezas")
public class NaturezasResource {
#GET
#Path("list/{code}")
#Produces(MediaType.APPLICATION_JSON)
public String listByLista(
#PathParam("code") codeListaNaturezasEnum code) {
try {
List<NaturezaORM> naturezas = this.naturezaSB
.listByListaNaturezas(code);
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(naturezas);
} catch (EntityNotFoundException e) { // No data found
logger.error("there is no Natures with the code " + code);
throw new HTTPException(404);
} catch (Exception e) { // Other exceptions
e.printStackTrace();
throw new HTTPException(500);
}
}
}
When I call the Rest Service with a code for which there are no results, the log message inside the EntityNotFoundException catch block is printed. However, my client receives a HTTP code 500 instead a 404. Why am I not receiving a 404 code?
Thanks,
Rafael Afonso
javax.xml.ws.http.HTTPException is for JAX-WS. JAX-RS by default doesnt know how to handle it unless you write an ExceptionMapper for it. So the exception bubbles up to the container level, which just sends a generic internal server error response.
Instead use WebApplicationException or one of its subclasses. Here a list of the exceptions included in the hierarchy, and what they map to (Note: this is only in JAX-RS 2)
Exception Status code Description
-------------------------------------------------------------------------------
BadRequestException 400 Malformed message
NotAuthorizedException 401 Authentication failure
ForbiddenException 403 Not permitted to access
NotFoundException 404 Couldn’t find resource
NotAllowedException 405 HTTP method not supported
NotAcceptableException 406 Client media type requested
not supported
NotSupportedException 415 Client posted media type
not supported
InternalServerErrorException 500 General server error
ServiceUnavailableException 503 Server is temporarily unavailable
or busy
You can find them also in the WebApplicationException link above. They will fall under one of the direct subclasses ClientErrorException, RedirectionException, or ServerErrorException.
With JAX-RS 1.x, this hierarchy doesn't exist, so you would need to do something like #RafaelAlfonso showed in a comment
throw new WebApplicationException(Response.Status.NOT_FOUND);
There are a lot of other possible constructors. Just look at the API link above
Spring Web 3.2 comes with a DeferredResult class for asynchronous request processing. It has a setErrorResult for providing an alternative response if something goes wrong, but no option to supply a http error code.
Surely it must be possible to control the http response code for failed requests.. How do I do that using the new Spring api?
The doc for setErrorResult method says the following:
Set an error value for the DeferredResult and handle it. The value may
be an Exception or Throwable in which case it will be processed as if
a handler raised the exception.
I suppose by setting an Exception, you may trigger an exception handler that returns the code you desire.
deferredResult.setErrorResult(new Exception());
This will always set the HTTP response code to 500. For finer control HttpServletResponse.setStatus seems to work.
This will work with user411180's client side.
public DeferredResult<List<Point>> getMessages(#RequestParam int reqestedIndex,
final HttpServletResponse response) {
final DeferredResult<List<Point>> deferredResult = new DeferredResult<>();
deferredResult.onCompletion(...);
deferredResult.onTimeout(new Runnable() {
#Override
public void run() {
deferredResult.setErrorResult("Explanation goes here.");
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); //or SC_NO_CONTENT
}
});
longPollRequests.put(deferredResult, reqestedIndex);
return deferredResult;
}
The exception that you pass as the argument to setErrorResult can be
annotated with #ResponseStatus. e.g. create an exception class of your own:
#ResponseStatus(HttpStatus.NOT_FOUND)
class NotFoundException extends RuntimeException {
// add your own constructors to set the error message
// and/or cause. See RuntimeException for valid ctors
}
Then in your code use it with the constructor you have created, for example:
deferredResult.setErrorResult(new NotFoundException(reason, cause));
Java Code:
#GET
#Path("/stop/{id}")
public void stop(
#PathParam("id") String id,
#Context HttpServletRequest request,
#Context HttpServletResponse response) throws ServletException,
IOException
{
server.stop(id);
}
Java Warning's being thrown to console:
WARNING: A HTTP GET method, public void com.myPackage.stop(java.lang.String,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) throws javax.servlet.ServletException,java.io.IOException, MUST return a non-void type.
You really shouldn't be using a GET operation.
I would use a POST operation and return a 201 Created with a link to a resource which describes the new state of the system.
For example, I would redirect to a shutdown status resource:
POST /stop/123
...
201 CREATED
Location:
http://acme.com/shutdownstatus/123
The the client can poll the resource to check on the status
GET /shutdownstatus/123
...
<shutdown xmlns="http://schemas.serverapp.com/shutdown">
<status>pending</status>
<message>Looks good so far</message>
</shutdown>
This new GET operation will always return the state of the server for that id. That way you know if it was shutdown correctly or not. If server shutdown takes a long time, the client could poll that resource to check on different shutdown statuses until it is complete. This way you can return from the original server shutdown request quickly.
If an exception was thrown in your process, I wouldn't return it to the client, I would have a status for the exception in the server status resource. I always avoid making a client handle an exceptional case when I can represent it as a resource. This allows you to change the resource freely, such as when the exception causing method is changed or fixed, without changing the external API.
The warning is correct. A GET operation should be idempotent, so shouldn't affect server state. If you're not returning anything, the method can't be doing anything useful. You should change it to POST or some other appropriate HTTP operation.
url must be as follows.
{servername}:{port}/{applicationname}/{standardname}/{your service name}/{your operation name}
ex: http://localhost:8080/restful/jersy/user/service/getUserDets
restful - applicationname
jersy - standardname {optional}
user/service - service name
getuserdets - operation name
Try to define it as *V*oid and return null.
#GET
#Path("/stop/{id}")
public void stop(
#PathParam("id") String id,
#Context HttpServletRequest request,
#Context HttpServletResponse response) throws ServletException,
IOException
{
server.stop(id);
return null;
}