Method: Head on /refresh is returning 500 - spring-boot

/refresh endpoint is added, exposed and I can call directly , but it is not avaialble via the HTTP Method Head ?
2017-02-21 15:00:08.913 INFO [-,,,] 4597 --- [main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/refresh || /refresh.json],methods=[POST]}" onto public java.lang.Object org.springframework.cloud.endpoint.GenericPostableMvcEndpoint.invoke()
Exception:
org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'HEAD' not supported
at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.handleNoMatch(RequestMappingInfoHandlerMapping.java:20

I think that this problem only happens when in your micro-service has a #RestController.
As I can see, here you are the difference handles in a micro-service with a #RestController:
2017-02-22 13:54:38.382 **ERROR** [micro-service-1,e9a053f5ffa72714,3980777f97a147f9,true] 10956 --- [http-nio-auto-3-exec-1] c.s.e.c.e.DefaultExceptionHandler
: ErrorResponse [errorCode=90000, description=Request method 'HEAD' not supported, correlationId=e9a053f5ffa72714, externalErrorCode=null, additionalProperties={}]
org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'HEAD' not supported
at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.handleNoMatch(RequestMappingInfoHandlerMapping.java:207)
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lookupHandlerMethod(AbstractHandlerMethodMapping.java:374)
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:314)
...
And here you are another one but in this case, has not a #RestController:
2017-02-22 15:14:49.795 **WARN** [micro-service-2,897590499c7c776c,
74a8108edccafb5e,true] 27623 --- [http-nio-auto-2-exec-5]
o.s.web.servlet.PageNotFound : Request method 'HEAD' not supported

I was able to resolve this with the following:
#Component
public class ActuatorHeadEndpoint extends EndpointMvcAdapter {
public ActuatorHeadEndpoint(RefreshEndpoint delegate) {
super(delegate);
}
#RequestMapping(method = RequestMethod.HEAD)
#ResponseBody
#Override
public Object invoke() {
if (!getDelegate().isEnabled()) {
return new ResponseEntity<>(Collections.singletonMap(
"message", "This endpoint is disabled"), HttpStatus.NOT_FOUND);
}
return new ResponseEntity<>("", HttpStatus.METHOD_NOT_ALLOWED);
}
}

fran thanks you are right, that solved the problem its because the class has a #ExceptionHandler(Exception.class) , which handles the unspecified exceptions by returning 500 and considers it as internal server error. explicitly defining the HttpRequestMethodNotSupportedException as #ExceptionHandler in the advice and handle it with the default actuator JSON response (405) which the spring boot admin expects , everything is normal.

This is a bug in Spring Boot Actuator. When the management port is different to server port the management stays without the DefaultHandlerExceptionResolver, which is responsible for returning error 405 when the method is not allowed.
This causes problems in Spring Boot Admin because it expects error 405 in some cases instead of any other else. It uses the HEAD method to verify if the endpoint exists. Call the endpoint with the correct method would execute the code, and the idea is only to verify if it exists.
https://github.com/spring-projects/spring-boot/issues/14084

Related

Error handling on quarkus mutiny rest client

On my quarkus rest project i have a restclient that uses mutiny:
#Path("/")
#RegisterRestClient(configKey = "my-api")
#RegisterClientHeaders
#RegisterProvider(MyExceptionMapper.class)
public interface MyClient {
#POST
#Path("path")
Uni<MyBean> get(String body);
}
I wanna handle propery non 2XX httpError so i have made my ExceptionMaper
public class MyExceptionMapper implements ResponseExceptionMapper<MyException> {
#Override
public MyException toThrowable(Response response) {
//TODO
return new MyException();
}
}
a bad call on the client shows that MyExceptionMapper handle the response but the exception raises and does not became a failure on my Uni Client response object
Uni<MyBean> bean = myClient.get("") // i do not have a failure in case of 4XX http
.onFailure().invoke(fail -> System.out.println("how can i get here?"));
Am i using mutiny on a rest client in the wrong way?
Thanks
UPDATE
ok i forgot to add the dependency quarkus-rest-client-mutiny, adding this i notice 2 things,
i still pass through Myexceptionmapper
i also produce a Uni.failure, but the exception into the failure is not the custom exception i created into MyExceptionmapper but a RestEasyWebApplicationException
Failure : org.jboss.resteasy.client.exception.ResteasyWebApplicationException: Unknown error, status code 400
at org.jboss.resteasy.client.exception.WebApplicationExceptionWrapper.wrap(WebApplicationExceptionWrapper.java:107)
at org.jboss.resteasy.microprofile.client.DefaultResponseExceptionMapper.toThrowable(DefaultResponseExceptionMapper.java:21)
Does the ExceptionMapper becomes useless in this context?
I think this is a bug in quarkus-rest-client-mutiny. I created an Github issue based on your findings.
It will work as you expect if you switch to quarkus-rest-client-reactive

Handle 403-error in Spring

I want to handle 403 error to show normal message:
#ExceptionHandler(AccessDeniedException.class)
#ResponseBody
public String accessDeniedException () {
return "my message";
}
But AccessDeniedException not handle 403 error.
Same not working follow:
#ResponseStatus(value = HttpStatus.FORBIDDEN)
#ExceptionHandler(SecurityException.class)
#ResponseBody
As I know, If an exception is not being thrown by the code called through your controller, you can't handle it by using #ExceptionHandler (or #ControllerAdvice). For example, exceptions thrown directly from Spring Security, like the CSRF exception, can't be caught this way.
This most likely is coming via Spring Security. If that's the case you need to setup and register an access-denied-handler.
Here is a detailed tutorial of how to do that.

How to handle HttpMediaTypeNotAcceptableException by writing error content to the response body using exception handler annotation?

When a client request for a resource producing application/json content with Accept Header of application/xml. The request fails with HttpMediaTypeNotAcceptableException exception and is wrapped into error message body in the response entity object by using exception handler annotation as mentioned in below code. However, we receive HttpMediaTypeNotAcceptableException again when return values are written to the response with HttpMessageConverter. It is because it checks the producible content type for the response with the acceptable request type, but this is exactly something we are trying to communicate to the client using error message. How do I workaround this issue ? Btw, all the other exceptions are parsing fine to error message. Please advise.
#ControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler {
#Override
protected ResponseEntity<Object> handleExceptionInternal(Exception ex, Object body,
HttpHeaders headers, HttpStatus status, WebRequest request) {
// Setting the response content type to json
headers.setContentType(MediaType.APPLICATION_JSON);
return ResponseEntity.status(status).headers(headers).body(body);
}
}
A few options come to my mind. One is that your controller method produces all content types and then you throw an exception in your method if the content type is not the one you are expecting, then the exception handler can take this exception and transform it. This is the only one that works with exception handlers, as exception handlers only deal with exceptions produced in the controller method.
The other options are:
Use an interceptor (but I'm not sure if this will work, as Spring might try to resolve first the controller method rather than invoking the interceptors).
Extend RequestMappingHandlerMapping to call the exception handler if it doesn't find a suitable method. You'll probably need to override the method handleNoMatch. In there you'll need to get a reference to the list of HandlerExceptionResolver
The first one is the simplest to understand, and the latest one might be the most 'extensible', but it also requires some understanding of the internals of Spring.
Resolved by setting different content negotiation strategy FixedContentNegotiationStrategy for ExceptionHandlerExceptionResolver and HeaderContentNegotiationStrategy for RequestResponseBodyMethodProcessor.
I have been using a serialized enum-based response (enum annotated with jackson #JsonFormat(shape = Shape.OBJECT) to standardize the error messages in my exception handler class and faced the same issue when it caught with a HttpMediaTypeNotAcceptableException.
The workaround is to set the media type you expect to return directly to the builder method available in the ResponseEntity.
The below code works fine for me.
#ExceptionHandler(HttpMediaTypeNotAcceptableException.class)
public final ResponseEntity<ResponseMessagesEnum> handleHttpMediaTypeNotAcceptableException(
HttpMediaTypeNotAcceptableException e, HttpServletRequest request) {
logger.error("No acceptable representation found for [{}] | supported {}", request.getHeader("Accept"), e.getSupportedMediaTypes());
return ResponseEntity.status(HttpStatus.BAD_REQUEST).contentType(MediaType.APPLICATION_JSON)
.body(ResponseMessagesEnum.EX_001);
}

Spring Asynchronous Processing Does not Return To View

I'm using the Spring MVC asyncronous processing but the controller does not return a view on web browser.
#RequestMapping(value = "/generateGM", method = RequestMethod.POST)
public Callable<ModelAndView> generateGMReport(#RequestParam("countryCode") int countryCode, ModelAndView mv) {
Callable<ModelAndView> c = new GenericCallable(countryCode, reportDao, mv);
return c;
}
#Override
public ModelAndView call() throws Exception {
List<CostReport> gmList = reportDao.generateGrossMarginReport(countryCode);
mv.setViewName("gmReport");
mv.addObject("gmList", gmList);
return mv;
}
I had tried to modify the code to return Callable but it still does not return to the specified view name.
I'm using JBoss 7.1 as.
There is warning during deployment :
WARN [org.jboss.as.ee] (MSC service thread 1-7)
JBAS011006: Not installing optional component
org.springframework.web.context.request.async.StandardServletAsyncWebRequest
due to exception: org.jboss.as.server.deployment.DeploymentUnitProcessingException:
JBAS011054:
Could not find default constructor for class
org.springframework.web.context.request.async.StandardServletAsyncWebRequest
Reason: Perhaps sitemesh cannot set the response object from Spring MVC framework (AsynContext).
What is the reason ?
Please help.
Thanks.
Since the Sitemesh filter does some post-processing at the end of a request, it needs to support the Servlet 3 async request feature in order for this to work. When the initial Servlet container thread exits and the response remains open. If the Sitemesh filter is unaware of this, it will attempt to complete processing to early.
I am not an expect on sitemesh. But it's a servlet also so they follow the "chain of command" pattern which means it's possible it fail to transfer the correct url you need. can you post you config for async spring and sitemesh config in web.xml
It may be helpful. Return as a String instead of ModelAndView.

Spring MVC annotated controller methods, unable to "find" method for DELETE operation

Here is the actual code:
#RequestMapping(value = "/competitors/{id}", method = RequestMethod.GET)
public Competitor getCompetitor(#PathVariable("id") long id)
{
Competitor competitor = competitorService.getCompetitorById(id);
if (null == competitor)
{
EmptyResultDataAccessException e = new EmptyResultDataAccessException(1);
logger.log(Level.WARN, e.getMessage());
throw e;
}
return competitor;
}
#RequestMapping(value = "/competitors/{id}", method = RequestMethod.DELETE)
public String deleteCompetitor(#PathVariable("id") long id)
{
Competitor competitor = new Competitor();
competitor.setId(id);
competitorService.deleteCompetitor(competitor);
return "Solid gone!";
}
Sending a DELETE request to /competitors/200 results in the error:
"HTTP Status 405 - Request method 'DELETE' not supported"
The logging from Spring confirms that no route to this method can be found:
5559 [tomcat-http--3] DEBUG org.springframework.web.servlet.DispatcherServlet - DispatcherServlet with name 'dispatcher' processing DELETE request for [/vrsboserver/competitors/200] 5562 [tomcat-http--3] DEBUG org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
- Matching patterns for request [/competitors/200] are [/competitors/{id}] 5565 [tomcat-http--3] DEBUG org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
- Mapping [/competitors/200] to handler 'com.gtspt.vrsboserver.controllers.CompetitorController#4fe7f80' 5565 [tomcat-http--3] DEBUG org.springframework.web.servlet.mvc.WebContentInterceptor - Looking up cache seconds for [/competitors/200] 5565 [tomcat-http--3] DEBUG org.springframework.web.servlet.mvc.WebContentInterceptor - Applying default cache seconds to [/competitors/200] 5566 [tomcat-http--3] DEBUG org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver
- Resolving exception from handler [com.gtspt.vrsboserver.controllers.CompetitorController#4fe7f80]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'DELETE' not supported 5567 [tomcat-http--3] DEBUG org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver
- Resolving exception from handler [com.gtspt.vrsboserver.controllers.CompetitorController#4fe7f80]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'DELETE' not supported 5568 [tomcat-http--3] DEBUG org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
- Resolving exception from handler [com.gtspt.vrsboserver.controllers.CompetitorController#4fe7f80]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'DELETE' not supported 5568 [tomcat-http--3] WARN org.springframework.web.servlet.PageNotFound - Request method 'DELETE' not supported
To which my response is "BUH?".
I had same problem. What helps and it's probably not the final solution but is working for me:
Change of annotations and parameters of the method deleteCompetitors. Remove id (method parameter too). Read the id parameter from HttpServletRequest.
#RequestMapping(value = "/competitors", method = RequestMethod.DELETE)
public String deleteCompetitor(HttpServletRequest request)
{
String idHeader = request.getHeader("id");
Integer id = Integer.valueOf(idHeader).intValue();
Competitor competitor = new Competitor();
competitor.setId(id);
competitorService.deleteCompetitor(competitor);
return "Solid gone!";
}
The id parameter is passed by header this way (code of the client - not complete):
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpDelete httpDelete = new HttpDelete...
...
httpDelete.setHeader("id", "123");
...
httpClient.execute(httpDelete);
I'm using the Apache HttpClient.
Normal browser only support get / post.
Spring resolved this by using a hidden parameter, to enable it, add below to your web.xml:
<filter>
<filter-name>httpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>httpMethodFilter</filter-name>
<servlet-name>springDispatcher</servlet-name>
</filter-mapping>
Try changing it to method = RequestMethod.GET and see if it works.
Did you try this http://www.codereye.com/2010/12/configure-tomcat-to-accept-http-put.html? This will only work of course of you are running on Tomcat. It seems that most app servers have disabled the ability to handle PUT and DELETE request be default.
Of course, enabling this will probably expose you to new security holes.
I ran into this problem recently. Here are a couple of my findings/comments:
I am running tomcat 7.0.42 with Spring 3.2.2
The following message is spit out on the log in all of these cases. 405 Method Not Allowed is returned to the client.
org.springframework.web.servlet.PageNotFound - Request method 'DELETE' not supported
The REST URL you are using is wrong. Even though the endpoint isn't there, you still get a 405.
You are not logged in and are not authorized to perform any action, let alone a DELETE
DELETE actually isn't supported because there is no function with method = RequestMethod.GET
Tomcat is blocking operations like DELETE, PUT, etc. due to the readonly init-param set to true
The method is present, DELETE is allowed, everything is fine except there was an uncaught runtime exception (e.g. Null Pointer Exception) in the method
With the exception of 3 and 4, the message shown and the response is very misleading. It sends you down investigation rabbit holes that end up fruitless.
What ended up being my problem is that we had a method like this:
public void deleteSomething(HttpServletRequest request, HttpServletResponse response, #PathVariable("id") long id, #RequestParam String objectName);
It SHOULD be this:
public void deleteSomething(HttpServletRequest request, HttpServletResponse response, #PathVariable("id") long id, #RequestParam("objectName") String objectName);
See the difference? It is the missing ("objectName") after #RequestParam. It compiles and runs fine in STS, but when deployed on a tomcat server directly, it doesn't work.
Thanks to #fmelan for the post above because it helped us find this small typo.
This doesn't look like it was your problem, but for anyone else who is stuck trying to figure out why 'DELETE' is not supported ...

Resources