Grizzly Servlet容器:允许带消息体的DELETE请求及400错误自定义需求
我碰到过不少类似的场景,这个问题的核心在于:JAX-RS容器(比如Jersey、RESTEasy这类实现)会在请求到达你的自定义ContainerRequestFilter之前,就对HTTP方法和请求体的匹配性做前置校验——按照REST规范,GET/DELETE这类方法本不应携带请求体,所以容器直接返回了400,但默认没有给出友好的错误提示。
下面给你两种针对性的解决思路,你可以根据业务需求选择:
思路一:允许DELETE请求携带消息体(忽略校验)
如果你的业务场景确实需要DELETE带请求体(虽然不符合REST最佳实践,但特殊场景下可以兼容),可以通过配置让JAX-RS容器接受这类请求:
针对Jersey框架
在你的应用配置类(继承ResourceConfig)中添加配置:
public class MyRestApplication extends ResourceConfig { public MyRestApplication() { // 指定允许携带请求体的HTTP方法,这里加上DELETE property("jersey.config.server.acceptRequestBodyForHttpMethods", "DELETE"); // 注册你的资源类和过滤器 packages("com.your.project.resources"); } }
配置完成后,DELETE请求的消息体就会被正常解析,不会再提前返回400,你的ContainerRequestFilter也能正常介入处理了。
针对RESTEasy框架
可以在web.xml中添加参数,或者在resteasy.properties配置文件里写入:
resteasy.allow.http.methods.with.body=DELETE
思路二:返回自定义友好错误提示(严格遵循规范)
如果你想严格遵守REST规范,同时给用户返回清晰的错误提示,那ContainerRequestFilter确实派不上用场——因为400错误是在它执行之前就被容器触发了。这时候可以用Servlet Filter来提前拦截请求:
自定义Servlet Filter示例
@WebFilter(urlPatterns = "/*") public class DeleteRequestBodyFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpReq = (HttpServletRequest) request; HttpServletResponse httpResp = (HttpServletResponse) response; // 判断是否是带请求体的DELETE请求 if ("DELETE".equalsIgnoreCase(httpReq.getMethod()) && hasRequestBody(httpReq)) { // 返回自定义错误响应 httpResp.setStatus(HttpServletResponse.SC_BAD_REQUEST); httpResp.setContentType("application/json;charset=UTF-8"); String errorJson = "{\"code\": 400, \"message\": \"DELETE请求不允许携带消息体,请移除请求体后重试\"}"; httpResp.getWriter().write(errorJson); return; } // 其他请求正常放行 chain.doFilter(request, response); } // 辅助方法:判断请求是否携带消息体 private boolean hasRequestBody(HttpServletRequest request) { return request.getContentLength() > 0 || "chunked".equalsIgnoreCase(request.getHeader("Transfer-Encoding")); } @Override public void init(FilterConfig filterConfig) throws ServletException {} @Override public void destroy() {} }
这个过滤器会在JAX-RS的前置校验之前执行,一旦检测到带请求体的DELETE请求,就直接返回你自定义的JSON错误提示,替代服务器默认的无提示400。
补充:Spring Boot环境的处理
如果你的项目用的是Spring MVC(而非JAX-RS),思路类似:Spring MVC默认允许DELETE带请求体,若要拦截并返回自定义错误,可以用HandlerInterceptor或者同样的Servlet Filter实现,逻辑和上面一致。
内容的提问来源于stack exchange,提问作者logi0517

