It seems the propertyserver.servlet-path in Spring Boot 1.5 has then been changed to server.servlet.path in Spring Boot 2.0 and spring.mvc.servlet.path in Spring Boot 2.1 (https://github.com/spring-projects/spring-boot/issues/12971)
With this last step, it seems it is not legal anymore to use a '*' in the path, in the form of:
spring.mvc.servlet.path=/*
See: https://github.com/spring-projects/spring-boot/issues/13292 I might be the one complaining about it.
/ and /* seems legit value as path, and in some cases, one may prefer to use /* for any reason (e.g. https://bluxte.net/musings/2006/03/29/servletpath-and-pathinfo-servlet-api-weirdness/)
In my case, I consider a project relying on a commercial library (i.e. no way to change their implementation), itself relying on CXF. For some API pathes, a ServletWrappingController redirects the call to some CXF Servlet (version 3.2.4), with a stack looking like:
Daemon Thread [http-nio-8080-exec-8] (Suspended (breakpoint at line 166 in ServletController))
owns: NioEndpoint$NioSocketWrapper (id=201)
ServletController.invoke(HttpServletRequest, HttpServletResponse, boolean) line: 166
ServletController.invoke(HttpServletRequest, HttpServletResponse) line: 160
CXFServlet(CXFNonSpringServlet).invoke(HttpServletRequest, HttpServletResponse) line: 216
CXFServlet(AbstractHTTPServlet).handleRequest(HttpServletRequest, HttpServletResponse) line: 301
CXFServlet(AbstractHTTPServlet).doGet(HttpServletRequest, HttpServletResponse) line: 225
CXFServlet(HttpServlet).service(HttpServletRequest, HttpServletResponse) line: 634
CXFServlet(AbstractHTTPServlet).service(ServletRequest, ServletResponse) line: 276
XXXServletWrappingController(ServletWrappingController).handleRequestInternal(HttpServletRequest, HttpServletResponse) line: 165
XXXServletWrappingController(AbstractController).handleRequest(HttpServletRequest, HttpServletResponse) line: 177
SimpleControllerHandlerAdapter.handle(HttpServletRequest, HttpServletResponse, Object) line: 52
DispatcherServlet.doDispatch(HttpServletRequest, HttpServletResponse) line: 1038
DispatcherServlet.doService(HttpServletRequest, HttpServletResponse) line: 942
DispatcherServlet(FrameworkServlet).processRequest(HttpServletRequest, HttpServletResponse) line: 998
DispatcherServlet(FrameworkServlet).doGet(HttpServletRequest, HttpServletResponse) line: 890
DispatcherServlet(HttpServlet).service(HttpServletRequest, HttpServletResponse) line: 634
DispatcherServlet(FrameworkServlet).service(HttpServletRequest, HttpServletResponse) line: 875
DispatcherServlet(HttpServlet).service(ServletRequest, ServletResponse) line: 741
At this point:
String pathInfo = request.getPathInfo() == null ? "" : request.getPathInfo();
is always null. It appears the whole path is in ther RequestPath of the undelrying HttpServletRequest, but the pathInfo remained empty.
This is workarounded by having spring.mvc.servlet.path=/*, in which case .getPathInfo returns the expected value (the whole path).
I'm not a pro with servlets. It might be an issue with CXF which might have been responsible for having look at request.getRequestURI(). Still, the issue was workarounded with previous SpringBoot by using server.servlet.path=/*
Comment From: philwebb
That's an interesting problem but it does feel like an issue in CXF or the commercial library. I think that this line might also need to consider getServletPath().
I'm not too keen to relax those rules again but it should be possible for you to create your own dispatcherServletRegistration @Bean in code and provide the mapping you need.
Comment From: blacelle
I agree about the probable root-cause.
I tried the following without success:
// Primary over the one in dispatcherServletAutoConfiguration
@Primary
@Bean(name = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
@ConditionalOnBean(value = DispatcherServlet.class,
name = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServletRegistrationBean apexDispatcherServletRegistration(DispatcherServlet dispatcherServlet,
WebMvcProperties webMvcProperties,
ObjectProvider<MultipartConfigElement> multipartConfigProvider) {
MultipartConfigElement multipartConfig = multipartConfigProvider.getIfAvailable();
String servletPath = webMvcProperties.getServlet().getPath();
if ("/wildcard".equals(servletPath)) {
servletPath = "/*";
}
DispatcherServletRegistrationBean registration =
new DispatcherServletRegistrationBean(dispatcherServlet, servletPath);
registration.setName(DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
if (multipartConfig != null) {
registration.setMultipartConfig(multipartConfig);
}
return registration;
}
I guess that, as the bean name is forced to DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME, trying to change the methodName and adding @Primary is non-sense. Am I required to deactivate manually the whole DispatcherServletAutoConfiguration?
Comment From: philwebb
Try the following:
@Bean
public DispatcherServletRegistrationBean dispatcherServletRegistration(
DispatcherServlet dispatcherServlet,
ObjectProvider<MultipartConfigElement> multipartConfig) {
DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(
dispatcherServlet, "/test/*");
registration.setName("dispatcherServlet");
registration.setLoadOnStartup(-1);
multipartConfig.ifAvailable(registration::setMultipartConfig);
return registration;
}
Comment From: philwebb
Given that the problem is not in Spring Boot itself, and there is a work-around, we'd prefer to keep the stricter rules around spring.mvc.servlet.path.
Please let us know if you can't get the manual DispatcherServletRegistrationBean registration to work.
Comment From: jonas-gbl
Thank you both, I had the exact same issue (AP?)
Comment From: blacelle
@jonas-gbl Yes AP. Feel free to contact me privately if you have more questions/issues regarding AP
Comment From: karthickrc
@blacelle I am also having same issue now. how did you resolve it?