修改Spring Boot 配置controller拦截所有非静态资源请求

最近在弄一个proxy功能的时候遇到了下面的情况:

  • Controller层面希望拦截并处理所有的的请求,当然这里面又需要排除静态资源的访问

因此我们又如下的Controller代码:

  @RequestMapping(value = "/**")
    public DeferredResult<ResponseEntity<String>> exec(HttpServletRequest request, HttpServletResponse response) {
        final DeferredResult<ResponseEntity<String>> deferredResult = new DeferredResult<>(TIMEOUT_IN_MILLISECONDS);
        //do something
        return deferredResult;
    }

但是上面的代码也会拦截所有的静态资源请求,因此需要对静态资源进行特殊处理。我们想到了使用ResourceHttpRequestHandler来完成。
但是默认情况下ResourceHttpRequestHandler的优先级比较低,这个可以在org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry中看到:

	/**
	 * Specify the order to use for resource handling relative to other {@link HandlerMapping}s
	 * configured in the Spring MVC application context.
	 * <p>The default value used is {@code Integer.MAX_VALUE-1}.
	 */
	public ResourceHandlerRegistry setOrder(int order) {
		this.order = order;
		return this;
	}

因此我们需要提高ResourceHttpRequestHandler的优先级,因此我们配置了如下的代码:

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
        registry.addResourceHandler("/healthcheck.html").addResourceLocations("/");
        registry.addResourceHandler("/**/*.js").addResourceLocations("/");
        registry.addResourceHandler("/**/*.html").addResourceLocations("/");
        registry.addResourceHandler("/**/*.css").addResourceLocations("/");
        registry.addResourceHandler("/**/*.jpg").addResourceLocations("/");
        registry.addResourceHandler("/**/*.png").addResourceLocations("/");
        registry.addResourceHandler("/**/*.gif").addResourceLocations("/");
        registry.addResourceHandler("/**/*.jpeg").addResourceLocations("/");
    }
}

(当然了这块配置的静态资源类型不够全,仅仅可以说明情况)上面的WebConfig中有一处核心代码就是:registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
这一行代码的作用就是使得org.springframework.web.servlet.resource.ResourceHttpRequestHandler拥有最高的优先级,这样当用户请求
/a.js,/a.css等静态资源的时候不会被@RequestMapping(value = "/**")给拦截住。
但是这样配置的话,当用户访问GET /getIp接口的时候,就会去tomcat的ROOT目录下寻找这个静态文件,而在我们的需求中,其实是希望这个请求被@RequestMapping(value = "/**")
给处理。现在却被当作了静态资源,这是因为Mapped URL path [/**]被静态资源给覆盖了。这一点可以从应用的启动日志中看出来:

[2018-03-06 13:58:38.712 localhost-startStop-1 INFO  o.s.w.s.m.m.a.RequestMappingHandlerMapping:549] Mapped "{[/**],methods=[POST || PUT || PATCH]}" onto public org.springframework.web.context.request.async.DeferredResult<org.springframework.http.ResponseEntity<java.lang.String>> com.qunar.tc.qcloudgateway.executor.controller.ExecutorController.execWithRequestBody(java.lang.String,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
[2018-03-06 13:58:38.713 localhost-startStop-1 INFO  o.s.w.s.m.m.a.RequestMappingHandlerMapping:549] Mapped "{[/**],methods=[POST || PUT],consumes=[multipart/form-data || application/x-www-form-urlencoded]}" onto public org.springframework.web.context.request.async.DeferredResult<org.springframework.http.ResponseEntity<java.lang.String>> com.qunar.tc.qcloudgateway.executor.controller.ExecutorController.execFileUpload(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse,org.springframework.web.multipart.MultipartHttpServletRequest)
[2018-03-06 13:58:38.714 localhost-startStop-1 INFO  o.s.w.s.m.m.a.RequestMappingHandlerMapping:549] Mapped "{[/**]}" onto public org.springframework.web.context.request.async.DeferredResult<org.springframework.http.ResponseEntity<java.lang.String>> com.qunar.tc.qcloudgateway.executor.controller.ExecutorController.exec(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
[2018-03-06 13:58:38.718 localhost-startStop-1 INFO  o.s.w.s.m.m.a.RequestMappingHandlerMapping:549] Mapped "{[/error],produces=}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
[2018-03-06 13:58:38.719 localhost-startStop-1 INFO  o.s.w.s.m.m.a.RequestMappingHandlerMapping:549] Mapped "{[/error]}" 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)
[2018-03-06 13:58:38.855 localhost-startStop-1 INFO  o.s.w.s.h.SimpleUrlHandlerMapping:373] Mapped URL path [/healthcheck.html] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
[2018-03-06 13:58:38.855 localhost-startStop-1 INFO  o.s.w.s.h.SimpleUrlHandlerMapping:373] Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
[2018-03-06 13:58:38.855 localhost-startStop-1 INFO  o.s.w.s.h.SimpleUrlHandlerMapping:373] Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
[2018-03-06 13:58:38.951 localhost-startStop-1 INFO  o.s.w.s.h.SimpleUrlHandlerMapping:373] Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
[2018-03-06 13:58:39.441 localhost-startStop-1 INFO  o.s.j.e.a.AnnotationMBeanExporter:434] Registering beans for JMX exposure on startup
[2018-03-06 13:58:39.462 localhost-startStop-1 INFO  c.qunar.tc.qcloudgateway.Application:57] Started Application in 9.063 seconds (JVM running for 13.7)

其中出现了2次Mapped URL path [/**],第一次是映射到controller上,第二次又映射到静态文件处理上面。继续看代码发现在org.springframework.boot.autoconfigure.web.WebMvcProperties
Path pattern used for static resources配置如下:

	/**
	 * Path pattern used for static resources.
	 */
	private String staticPathPattern = "/**";

到这里以后,问题就好解决了,在application.properties中增加如下的配置

spring.mvc.static-path-pattern=/resources/**

将这个staticPathPattern的值覆盖掉,这样就不会出现上面的`Mapped “{[/**]}”被覆盖了,如上操作以后我们重启应用检查:

[2018-03-06 14:07:21.363 localhost-startStop-1 INFO  o.s.w.s.m.m.a.RequestMappingHandlerMapping:549] Mapped "{[/**],methods=[POST || PUT || PATCH]}" onto public org.springframework.web.context.request.async.DeferredResult<org.springframework.http.ResponseEntity<java.lang.String>> com.qunar.tc.qcloudgateway.executor.controller.ExecutorController.execWithRequestBody(java.lang.String,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
[2018-03-06 14:07:21.364 localhost-startStop-1 INFO  o.s.w.s.m.m.a.RequestMappingHandlerMapping:549] Mapped "{[/**],methods=[POST || PUT],consumes=[multipart/form-data || application/x-www-form-urlencoded]}" onto public org.springframework.web.context.request.async.DeferredResult<org.springframework.http.ResponseEntity<java.lang.String>> com.qunar.tc.qcloudgateway.executor.controller.ExecutorController.execFileUpload(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse,org.springframework.web.multipart.MultipartHttpServletRequest)
[2018-03-06 14:07:21.365 localhost-startStop-1 INFO  o.s.w.s.m.m.a.RequestMappingHandlerMapping:549] Mapped "{[/**]}" onto public org.springframework.web.context.request.async.DeferredResult<org.springframework.http.ResponseEntity<java.lang.String>> com.qunar.tc.qcloudgateway.executor.controller.ExecutorController.exec(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
[2018-03-06 14:07:21.370 localhost-startStop-1 INFO  o.s.w.s.m.m.a.RequestMappingHandlerMapping:549] Mapped "{[/error],produces=}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
[2018-03-06 14:07:21.370 localhost-startStop-1 INFO  o.s.w.s.m.m.a.RequestMappingHandlerMapping:549] Mapped "{[/error]}" 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)
[2018-03-06 14:07:21.531 localhost-startStop-1 INFO  o.s.w.s.h.SimpleUrlHandlerMapping:373] Mapped URL path [/healthcheck.html] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
[2018-03-06 14:07:21.531 localhost-startStop-1 INFO  o.s.w.s.h.SimpleUrlHandlerMapping:373] Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
[2018-03-06 14:07:21.532 localhost-startStop-1 INFO  o.s.w.s.h.SimpleUrlHandlerMapping:373] Mapped URL path [/resources/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
[2018-03-06 14:07:21.630 localhost-startStop-1 INFO  o.s.w.s.h.SimpleUrlHandlerMapping:373] Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]

从上面的日志可以看到现在/**正确映射到了我们想要的地方。

本文版权归作者所有,禁止一切形式的转载,复制等操作
赞赏

微信赞赏支付宝赞赏

发表评论

电子邮件地址不会被公开。 必填项已用*标注