9

我有一个简单的方法(在 Tomcat 6.0.35 上运行),如下所示:

@RequestMapping(value = "/bla/d", method = RequestMethod.DELETE)
@ResponseStatus(HttpStatus.NO_CONTENT)
public void d(@RequestParam String d){
    //logic here
}

当我发送带有类似帖子的参数的 DELETE 请求(正文中的 d=gggg)时,我收到 400 错误请求。但是,如果我将其更改为

@RequestMapping(value = "/bla/d", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.NO_CONTENT)
public void d(@RequestParam String d){
    //logic here
}

它完美地工作。我正在使用 Firefox 附加组件对其进行测试(以及 python 和 Spring 的 RestTemplate 具有相同的结果)这是请求在 POST 中的外观(a 是一个名为 a 并带有参数 a 的应对粘贴方法):

POST /bla/a HTTP/1.1
Host: ~~~~:8080
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/20100101 Firefox/13.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Content-Length: 7
Pragma: no-cache
Cache-Control: no-cache
a=asdas

HTTP/1.1 204 No Content
Server: Apache-Coyote/1.1
Date: Tue, 12 Jun 2012 09:29:46 GMT

删除看起来像:

DELETE /bla/d HTTP/1.1
Host: ~~~~~:8080
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/20100101 Firefox/13.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Content-Length: 7
d=asdas

HTTP/1.1 400 Bad Request
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Length: 971
Date: Tue, 12 Jun 2012 09:30:04 GMT
Connection: close

请帮助我,我可能错过了一些愚蠢的东西,但我看不到它。我最初的问题是通过带有 DELETE 请求的 post-like body 发送一个数组,但似乎更基本的东西是错误的。

4

3 回答 3

16

在做了一些研究和调试之后,我发现 Spring 的 ServletWebREquest 调用了 org.apache.catalina.connector.RequestFacade.getParameterValues 的 getParameterValues,它调用了 getParameterValues,我在其中找到了以下行(Request.java 2599-2600):

if (!getMethod().equalsIgnoreCase("POST"))
return;

这会杀死任何使用 DELETE 发送类似 POST 的参数的尝试,这意味着即使 RFC不限制此类使用,Tomcat 也会主动限制此用例(尽管它确实说某些现有实现可能会拒绝此类请求,但 Tomcat 只是抛出它的参数离开)。是什么带来了一个使用 Spring 和 Tomcat 并尝试向丑陋的解决方案发送带有参数的 DELETE 请求的原因,例如使用 @RequestBody 获取所有请求正文并手动提取它,这使得您所谓的无辜方法只想删除一些知道某个 Map 的东西包含请求正文。

@fmucar

于 2012-06-13T14:05:40.103 回答
0

我遇到了类似的问题,我发现的解决方案是在查询字符串中添加字段。我仍然想知道以这种方式排除表单主体的原因,但目前这是一种解决方法。

因此,对于您的示例,这意味着将 ?a=asdas 添加到 Host: ~~~~~:8080 URL。

我正在使用 spring-webmvc:3.2.4.RELEASE 所以我不确定这是否适用于您的版本。

于 2014-08-08T00:08:29.953 回答
0

这是一篇很老的帖子,但如果其他人正在寻找如何在 DELETE 方法上启用 @RequestParam,这就是我在 tomcat 8.5.4 上所做的。

@Value("${server.parseBodyMethods}")
private String parseBodyMethods;

@Bean
public TomcatEmbeddedServletContainerFactory containerFactory() {
    return new TomcatEmbeddedServletContainerFactory() {
        protected void customizeConnector(Connector connector) {
            super.customizeConnector(connector);
            connector.setParseBodyMethods(parseBodyMethods);
        }
    };
}

将“POST,DELETE”插入该定制器,您的删除请求参数应该开始工作。

我在 org.apache.catalina.connector.Connector 中找到了 parseBodyMethods,这里是 Tomcat 的文档:

这在想要支持 PUT 请求的 POST 样式语义的 RESTful 应用程序中很有用。请注意,除了 POST 之外的任何设置都会导致 Tomcat 的行为方式违背 servlet 规范的意图。根据 HTTP 规范,此处明确禁止使用 HTTP 方法 TRACE。默认为 POST ( Source )

于 2016-12-09T22:11:33.830 回答