Skip to content

Rest service with Spring Boot and Jersey incorrectly returns HTTP Status 404 when resource exist and method is not allowed #3132

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
johanhammar opened this issue Jun 5, 2015 · 2 comments

Comments

@johanhammar
Copy link

Hi!

Description
I've developed a small Rest API using Spring Boot and Jersey. It seems to work well except for when calling the Rest API with a method that is not allowed, i.e calling the service with PUT and only GET is allowed. This leads to a HTTP 404 Not Found instead of HTTP 405 Method Not Allowed.

Workaround
Setting an alternative base path using @ApplicationPath, i.e. @ApplicationPath("/api") results in HTTP 405 Method Not Allowed as expected.

It should be possible to map the api to / using Jersey.

Thanks!

@candlejack297
Copy link

I noticed this as well. The interesting thing is that response still returns the Allow header with the proper methods, so I assume the status is just being set incorrectly somewhere.

Also, I'm not sure whether this is part of the same issue. But I can't seem to get 405, 406, or 415 errors either, unless I use the same workaround. There has to be some configuration with the root handler that I'm missing.

Update: Found a link: #2025. And a workaround for myself: It seems like changing the dependency from spring-boot-starter-web to spring-boot-starter-jersey fixes the issue.

Here are the lines that are different during server startup.

2015-07-16 19:58:07.776  INFO 50853 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Overriding bean definition for bean 'beanNameViewResolver': replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter.class]]

2015-07-16 19:58:09.893  INFO 50853 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2015-07-16 19:58:09.895  INFO 50853 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'dispatcherServlet' to [/]

2015-07-16 19:58:10.825  INFO 50853 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@23c30a20: startup date [Thu Jul 16 19:58:07 PDT 2015]; root of context hierarchy
2015-07-16 19:58:10.912  INFO 50853 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2015-07-16 19:58:10.912  INFO 50853 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],methods=[],params=[],headers=[],consumes=[],produces=[text/html],custom=[]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest)
2015-07-16 19:58:10.947  INFO 50853 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2015-07-16 19:58:10.947  INFO 50853 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2015-07-16 19:58:11.010  INFO 50853 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Nov 30, 2015
@wilkinsona
Copy link
Member

You can map the API to / when using Jersey, but you have to ensure that Spring MVC isn't also using the same path. When they're both using the same path, Jersey can't handle the PUT so Spring MVC tries instead. It doesn't have a mapping for / so it responds with a 404. If you want to map Jersey to / and use Spring MVC, then you need to set server.context-path to move Spring MVC out of the way.

The workaround described by @candlejack297 switches off the auto-configuration of Spring MVC so it's no longer mapped to / and no longer competes with Jersey for the same path.

@wilkinsona wilkinsona removed the status: waiting-for-triage An issue we've not yet triaged label Dec 3, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants