好的,我成功了。答案有点棘手,所以我想在这里注册,以防有人遇到这样的问题。
@Neil McGuigan 在他的评论中为我指出了正确的方向,但我一开始没有注意。这里的罪魁祸首是一个非常非常very我们的远程应用程序端的 API 设计很糟糕。
_method
是一个用于指定非标准 HTTP 动词的字段,例如PUT
, PATCH
, DELETE
, TRACE
等等。该字段的过滤条件为HiddenHttpMethodFilter
和HttpServletRequest
是用这个“新”方法包装的。你可以看到文件的来源 https://github.com/spring-projects/spring-framework/blob/master/spring-web/src/main/java/org/springframework/web/filter/HiddenHttpMethodFilter.java#L52怎么运行的。
正如我想要的_method
字段来通过过滤器而不修改整个请求(并导致错误,因为没有这样的动词ping
or message
在`RequestMethod)上,我首先必须停用过滤器。这可以通过两种方式完成:
我可以阻止 Spring Boot 自动配置 Spring MVC,跳过WebMvcAutoConfiguration
从被加载时ApplicationContext
已加载。你可以想象这是一个很大、很大、很大的NO因为,嗯,things http://giphy.com/gifs/HhTXt43pk1I1W/fullscreen可能会发生。
-
我可以用一个FilterRegistrationBean
禁用坏过滤器。非常简单明了,这是我选择使用的方法:
@Bean
public FilterRegistrationBean registration(HiddenHttpMethodFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean(filter);
registration.setEnabled(false);
return registration;
}
最后但并非最不重要的一点是,我决定给予HiddenHttpMethodFilter
以某种方式进行一点扩展improve请求是如何通过的。 Java EE 规范在 Servlet 规范命令中非常明确,它指出:
Thou should不改变你方的要求。您必须尊重发件人(类似的事情)
虽然我同意这一点,但为了我的心理稳定,我还是决定改变它。为了实现这一点,我们可以使用一个简单的HttpServletRequestWrapper
,覆盖所选方法并使用包装部分过滤原始请求。我最终做了这样的事情:
public class WhatoolsHiddenHttpMethodFilter extends OrderedHiddenHttpMethodFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String paramValue = request.getParameter(OrderedHiddenHttpMethodFilter.DEFAULT_METHOD_PARAM);
if("POST".equals(request.getMethod()) && StringUtils.hasLength(paramValue)) {
String method = paramValue.toUpperCase(Locale.ENGLISH);
List<String> whatoolsMethods = Arrays.asList("ping", "message", "carbon", "media", "media_carbon", "ack");
if(whatoolsMethods.contains(paramValue)){
WhatoolsHiddenHttpMethodFilter.HttpMethodRequestWrapper wrapper = new WhatoolsHiddenHttpMethodFilter
.HttpMethodRequestWrapper(request, "POST", paramValue);
filterChain.doFilter(wrapper, response);
} else {
WhatoolsHiddenHttpMethodFilter.HttpMethodRequestWrapper wrapper = new WhatoolsHiddenHttpMethodFilter
.HttpMethodRequestWrapper(request, method, null);
filterChain.doFilter(wrapper, response);
}
} else {
filterChain.doFilter(request, response);
}
}
private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {
private final String method;
private final String whatoolsMethod;
public HttpMethodRequestWrapper(HttpServletRequest request, String method, String whatoolsMethod) {
super(request);
this.method = method;
this.whatoolsMethod = whatoolsMethod;
}
@Override
public String getMethod() {
return this.method;
}
@Override
public String getHeader(String name) {
if("x-whatools-method".equals(name)){
return this.whatoolsMethod;
}
return super.getHeader(name);
}
@Override
public Enumeration<String> getHeaderNames() {
List<String> names = Collections.list(super.getHeaderNames());
if(this.whatoolsMethod != null){
names.add("x-whatools-method");
}
return Collections.enumeration(names);
}
}
}
所以,它所做的就是用一个新的包装请求x-whatools-method
当标题位于我的标题中时whatoolsMethods
列表。有了这个,我可以轻松使用@RequestMapping
's headers
属性并将请求映射到正确的控制器方法。
回到最初的问题,我几乎可以肯定(嗯,99.95% 应该完全确定,但我们不要冒险)params
属性于@RequestMapping
仅适用于 GET URI 上的请求参数,例如http://foo.bar/?baz=42
。它无法过滤请求正文中发送的参数。
感谢尼尔的指导,即使很小!我希望这可以帮助别人。