spring - 为什么Spring在application/json get请求上解码+(加号字符)?我该怎么办?

标签 spring url encoding resttemplate

我有一个 Spring 应用程序,它接收类似 http://localhost/foo?email=foo+bar@example.com 的请求。这会触发一个 Controller ,大致如下所示:

@RestController
@RequestMapping("/foo")
public class FooController extends Controller {
    @GetMapping
    public void foo(@RequestParam("email") String email) {
       System.out.println(email)
    }
}

当我可以访问电子邮件时,它已转换为foo bar@example.com,而不是原来的foo+bar@example.com。根据When to encode space to plus (+) or %20?这应该只发生在内容为 application/x-www-form-urlencoded 的请求中。我的请求的内容类型为 application/json。请求的完整 MIME header 如下所示:

=== MimeHeaders ===
accept = application/json
content-type = application/json
user-agent = Dashman Configurator/0.0.0-dev
content-length = 0
host = localhost:8080
connection = keep-alive

为什么 Spring 将加号解码为空格?如果这是它应该工作的方式,why isn't it encoding pluses as %2B when making requests

我发现了这个错误报告:https://jira.spring.io/browse/SPR-6291这可能意味着这在版本 3.0.5 上已修复,并且我正在使用 Spring > 5.0.0。我可能会误解有关错误报告的某些内容。

我还发现了有关 RestTemplate 对这些值的处理的讨论:https://jira.spring.io/browse/SPR-5516 (我的客户正在使用 RestTemplate)。

所以,我的问题是,Spring 为什么要这样做?我怎样才能禁用它?我应该禁用它还是应该在客户端上对 pluses 进行编码,即使请求是 json?

澄清一下,我在这里没有使用 HTML 或 JavaScript。有一个 Spring Rest Controller,客户端是 Spring 的 RestTemplateUriTemplateUriComponentsBuilder,它们都不会按照 Spring 解码的方式对加号进行编码。

最佳答案

原始答案

您正在混合两件事,请求正文中的 + 意味着当 header 具有 application/x-www-form-urlencoded 时有一个空格。请求的正文或内容取决于 header ,但请求可以只有 url,没有 headers,也没有 body

因此 URI 的编码不能由任何 header 控制

请参阅 https://en.wikipedia.org/wiki/Query_string 中的 URL 编码 部分。

Some characters cannot be part of a URL (for example, the space) and some other characters have a special meaning in a URL: for example, the character # can be used to further specify a subsection (or fragment) of a document. In HTML forms, the character = is used to separate a name from a value. The URI generic syntax uses URL encoding to deal with this problem, while HTML forms make some additional substitutions rather than applying percent encoding for all such characters. SPACE is encoded as '+' or "%20".[10]

HTML 5 specifies the following transformation for submitting HTML forms with the "get" method to a web server.1 The following is a brief summary of the algorithm:

Characters that cannot be converted to the correct charset are replaced with HTML numeric character references[11] SPACE is encoded as '+' or '%20' Letters (A–Z and a–z), numbers (0–9) and the characters '*','-','.' and '_' are left as-is All other characters are encoded as %HH hex representation with any non-ASCII characters first encoded as UTF-8 (or other specified encoding) The octet corresponding to the tilde ("~") is permitted in query strings by RFC3986 but required to be percent-encoded in HTML forms to "%7E".

The encoding of SPACE as '+' and the selection of "as-is" characters distinguishes this encoding from RFC 3986.

您也可以从下面的屏幕截图中看到 google.com 上的相同行为

+ translated to space

%2B translated to +

您也可以在其他框架中看到相同的行为。下面是Python Flask的示例

Flask Demo

所以您所看到的是正确的,您只是将其与引用请求正文内容而不是 URL 的文档进行比较

编辑 1:5 月 22 日

调试后似乎在 Spring 中甚至没有发生解码。我发生在 package org.apache.tomcat.util.buf;UDecoder

/**
 * URLDecode, will modify the source.
 * @param mb The URL encoded bytes
 * @param query <code>true</code> if this is a query string
 * @throws IOException Invalid %xx URL encoding
 */
public void convert( ByteChunk mb, boolean query )
    throws IOException
{
    int start=mb.getOffset();

下面是转换实际发生的地方

    if( buff[ j ] == '+' && query) {
        buff[idx]= (byte)' ' ;
    } else if( buff[ j ] != '%' ) {

这意味着它是一个嵌入式 tomcat 服务器来执行此转换,而 spring 甚至不参与此操作。如类代码中所示,没有配置可以更改此行为。所以你必须忍受它

关于spring - 为什么Spring在application/json get请求上解码+(加号字符)?我该怎么办?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50270372/

相关文章:

PHP,验证用户提交的具有特定域的 URL

node.js - Node 无法通过管道传输 pdf 响应

c - 为什么多字节字符到 char32_t 的转换使用 UTF-8 作为多字节编码而不是特定于语言环境的编码?

Spring @RequestMapping 消耗字符集?

python - 如何在 Django 中描述 URL - 仍然需要一个答案

php - 获取唯一 ID 并用作页面的 url

php - Unicode编码错误: 'ascii' codec can't encode characters in position 360-362: ordinal not in range(128)

spring - Apache Tapestry 5.3 IoC 与 Spring 4 IoC

Eclipse 中的 Java Spring 检查

spring - 在 Spring MVC 中使用 PUT 和 DELETE 方法