java - 为什么 Spring 优先处理 405 Http Error 而不是 406 Http Error

标签 java web-services http rest spring-mvc

我在 Spring 3.1 中有一个休息 Controller ,它允许 GET 和 POST 方法。

POST 方法仅限于使用映射生成输出

@RequestMapping(value = "projects", method = RequestMethod.POST, Produce={"application/json"})

如果我 POST 下一个请求,它会返回带有“Allow: GET” header 的 405 错误。

POST /resources/projects
Content-Type: application/json
Accept: text/html

我发现Spring MVC框架在handleNoMatch方法中优先处理RequestMappingInfoHandlerMapping.java中的405错误。

protected HandlerMethod handleNoMatch(Set<RequestMappingInfo> requestMappingInfos, String lookupPath, HttpServletRequest request) throws ServletException {
....
....
    if (!allowedMethods.isEmpty()) {
        throw new HttpRequestMethodNotSupportedException(request.getMethod(), allowedMethods);
    }
    else if (!consumableMediaTypes.isEmpty()) {
        MediaType contentType = null;
        if (StringUtils.hasLength(request.getContentType())) {
            contentType = MediaType.parseMediaType(request.getContentType());
        }
        throw new HttpMediaTypeNotSupportedException(contentType, new ArrayList<MediaType>(consumableMediaTypes));
    }
    else if (!producibleMediaTypes.isEmpty()) {
        throw new HttpMediaTypeNotAcceptableException(new ArrayList<MediaType>(producibleMediaTypes));
    }

但是我希望我的 REST API 优先处理 406 错误,因为这是有意义的,我的优先级正确吗?我怎样才能实现这一目标?

我知道这个问题在 Spring 3.2 中已得到解决,但我无法升级到 3.2。

有人建议我扩展 RequestMappingInfoHandlerMapping,但我不知道该怎么做。

最佳答案

我认为您的应用程序配置不正确。 @RequestMapping 与您显示的不同,或者它在未注册的 @Controller 中注释了一个方法。

以下是使用我的 DispatcherServlet 注册的唯一映射

@RequestMapping(value = "projects", method = RequestMethod.POST, produces = { "application/json" })
public String home() {
    System.out.println("HomeController: Passing through...");
    return "WEB-INF/views/home.jsp";
}

并测试

CloseableHttpClient httpClient = HttpClientBuilder.create().build();
HttpPost post = new HttpPost("http://localhost:8080/resources/projects");
post.setHeader("Context-type", "application/json");
post.setHeader("Accept", "text/html");
HttpResponse httpResponse = httpClient.execute(post);
System.out.println(httpResponse);

我明白

HTTP/1.1 406 Not Acceptable [Server: [...]]

正如预期的那样。

您应该仔细检查日志以查看您想要的处理程序方法是否确实已注册。日志将显示类似

2013-11-30 01:30:33,958 [localhost-startStop-1] INFO  o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped "{[/projects],methods=[POST],params=[],headers=[],consumes=[],produces=[application/json],custom=[]}" onto public java.lang.String xyz.spring.mvc.HomeController.home() 

在您发表评论和建议的更改之后

@RequestMapping(value = "projects", method = RequestMethod.POST, produces = { "application/json" })
public String home() {
    System.out.println("HomeController: Passing through...");
    return "WEB-INF/views/home.jsp";
}

@RequestMapping(value = "projects", method = RequestMethod.GET)
public String homeGet() {
    System.out.println("HomeControllerGet: Passing through...");
    return "WEB-INF/views/home.jsp";
}

这是启动日志

2013-12-02 08:33:57,233 [localhost-startStop-1] INFO  o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped "{[/projects],methods=[POST],params=[],headers=[],consumes=[],produces=[application/json],custom=[]}" onto public java.lang.String xyz.sample.baremvc.HomeController.home() 
2013-12-02 08:33:57,234 [localhost-startStop-1] INFO  o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped "{[/projects],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String xyz.sample.baremvc.HomeController.homeGet() 

Tomcat 仍然给我一个 406

HTTP/1.1 406 Not Acceptable [[...]]

这是有道理的。请记住 Produces 属性的 javadoc 状态

The format is a single media type or a sequence of media types, with a request only mapped if the Accept matches one of these media types.

由于您的请求具有与媒体类型不匹配的 Accept header ,因此该请求 Not Acceptable ,并且会出现 406。

关于java - 为什么 Spring 优先处理 405 Http Error 而不是 406 Http Error,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20288225/

相关文章:

java - TDD,不可能有异常(exception)

java - HTTP请求参数消耗: Camel SU issue

java - 使用Web服务开发带有服务器的Android应用程序

java - 使用 RestTemplate 的 spring webservices 的超时配置

python - 如何使用 Python 将多部分 PDF 请求发送到 OneNote

java - 我无法登录或注册我的应用程序

java - 访问aspectj中的私有(private)字段

javascript - Node Js Express 路由器不工作

http - Camel Jetty 组件写入输出流

http - 在 Yahoo Pipes 中使用 HTTPS 资源?