当前位置: 首页 > 知识库问答 >
问题:

为什么Spring对应用程序/json get请求进行反编码(加号)?我该怎么办呢?

贝杜吟
2023-03-14

我有一个Spring应用程序,它接收像http://localhost/foo?email=foobar@example.com这样的请求。这将触发一个大致如下所示的控制器:

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

当我可以访问电子邮件时,它已经被转换成foobar@example.com而不是原来的foobar@example.com。根据何时将空间编码为加号()或?这只应发生在内容为application/x-www-form-urlencoded的请求中。我的请求的内容类型为application/json。请求的完整MIME头如下所示:

=== 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将加号解码为空格?如果这是它应该工作的方式,为什么在发出请求时不将加号编码为+

我发现了这个错误报告:https://jira.spring.io/browse/SPR-6291这可能意味着这是固定的版本3.0.5和我使用Spring

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

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

我只是想澄清一下,我没有在任何地方使用HTML或JavaScript。有一个Spring Rest控制器,客户端是Spring的RestTemplateUriTemplateUriComponentsBuilder,它们都没有像Spring解码那样编码加号。


共有3个答案

左丘繁
2023-03-14

如果您有此请求:

http://localhost/foo?email=foo+bar@example.com

那么原来是foobar@example.com。如果你说原始的应该是foobar@example.com那么请求应该是:

http://localhost/foo?email=foo%2Bbar@example.com

所以,Spring是工作的预期。也许在客户端上,您应该检查URI是否正确编码。客户端URL编码负责构建正确的HTTP请求。

如果在JavaScript中生成请求,请参见encodeURI();如果在Spring中生成请求,请参见uriToString()。

构建您的请求字符串之后的部分?),没有任何编码,使用未编码的值,如foobar@email.com,并且只有在最后,在实际使用它之前,在GET中,使用客户端平台上可用的任何内容对其进行编码。如果您想使用POST,那么您应该根据您选择的MIME类型对其进行编码。

司寇旺
2023-03-14

SPR-6291在v3中修复了此问题。0.5但在其他一些情况下,如SPR-11047,这一问题仍未解决。虽然SPR-6291的优先级较高,但SPR-11047的优先级较低。

去年我在旧春开发RESTAPI时遇到了这个问题。我们可以通过多种方式在Springcontroller中获取数据。其中两个是通过@RequestParam@PathVariable注释实现的

正如其他人提到的,我认为它是spring的内部问题,并不是专门属于URL编码,因为我是通过POST请求发送数据的,但它有点编码问题。但我也同意其他人的看法,因为现在它只在URL中存在问题。

因此,我知道有两种解决方案:

>

  • 您可以使用@PathVariable而不是@RequestParam,因为从SPR-6291开始,这个加号问题在@PathVariable中得到了解决,并且仍然作为SPR-11047@RequestParam保持打开状态

    我的spring版本甚至没有通过@PathVariable注释接受加号,所以这就是我克服问题的方法(我一步一步记不起来了,但它会给你提示)。

    在您的情况下,您可以在发送请求之前通过JSescape加号获取字段。大概是这样的:

    var email = document.getElementById("emailField").value;
    email = email.replace('+', '%2B');
    

  • 顾穆冉
    2023-03-14

    原始答案

    您混合了两件事,请求主体中的意味着当标头具有application/x-www-form-urlencoded时,会有一个空格。请求的正文或内容取决于标题,但请求只能有url和noheaders和nobody

    因此,URI的编码不能由任何标题本身控制

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

    某些字符不能是URL的一部分(例如空格),而其他一些字符在URL中具有特殊含义:例如,字符#可用于进一步指定文档的子部分(或片段)。在HTML表单中,字符=用于分隔名称和值。URI通用语法使用URL编码来处理此问题,而HTML表单进行一些额外的替换,而不是对所有此类字符应用百分比编码。空间编码为“”或“”。[10]

    HTML5指定以下转换,用于使用“get”方法将HTML表单提交到web服务器。1以下是算法的简要总结:

    无法转换为正确字符集的字符将替换为HTML数字字符引用[11]空间编码为“”或“”字母(A–Z和A–Z)、数字(0–9)以及字符“*”、“-”、“.”和“\”保持不变,所有其他字符编码为%HH十六进制表示,任何非ASCII字符首先编码为UTF-8(或其他指定编码)。RFC3986允许在查询字符串中使用与波浪号(~)对应的八位字节,但要求在HTML格式中以百分比编码为“~”。

    将空间编码为“”并选择“按原样”字符将此编码与RFC 3986区分开来。

    你可以在google上看到同样的行为。com以及下面的屏幕截图

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

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

    编辑-1:22五月

    调试之后,似乎解码在Spring都没有发生。我发生在包组织中。阿帕奇。公猫util。bufUDecoder

    /**
     * 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甚至不参与此转换。在类代码中没有更改此行为的配置。所以你必须接受它

     类似资料:
    • 问题内容: FindBugs报告一个错误: 依赖默认编码找到了对将执行字节到字符串(或字符串到字节)转换的方法的调用,并假定默认平台编码是合适的。这将导致应用程序行为在平台之间有所不同。使用备用API并明确指定字符集名称或字符集对象。 我像这样使用FileReader(仅是一段代码): 要更正错误,我需要更改 至 当我使用PrintWriter时,发生了相同的错误。所以现在我有一个问题。什么时候可

    • 问题内容: 我提出的问题可能更多是与浏览器相关的问题,但是当我冒险构建Web应用程序时,我也想找到答案。 在我的客户端代码中,我正在打电话。该帖子可能需要一段时间才能回复。我看到的是经过一定时间后再次发送请求。 我以为是我的电话再次发送了,但是无论我在服务器上看到多少次POST请求,我都只会看到一次回调。我相当确定我的代码不会多次发送,因此我认为浏览器会重试吗? 我知道我的服务器在运行Wiresh

    • 问题内容: 我的网站几乎完成了,除了最后一部分,我需要使图库页面支持ajax才能使用Ajax更改页码。 图库页面视图: Dajax / Dajaxice的记录不是很好…我只需要显示一些图像即可。 问题答案: 这是使用Dajax / Dajaxice的方法,这是为了在Django中简化AJAX: 根据文档安装Dajaxice和Dajax。文档似乎没有提及它,但是您也可以使用,即 pip instal

    • 问题内容: 当我尝试启动我们的Java服务器时,出现此错误:java.lang.ClassNotFoundException:com.mysql.jdbc.Driver 但是我在脚本所在的文件夹中有mysql-connector-java-5.1.22-bin.jar,并在运行脚本时使用它: 但是仍然得到这个。该怎么办?我正在使用CentOS服务器。 问题答案: 在中的 MANIFEST.MF 文

    • 我有一个在端口3001上运行的节点后端服务器,以及一个我尝试代理到该端口以获取数据的反应服务器。 现在,我已经在客户端文件夹的package.json文件中包含了“代理”行,告诉React将请求代理到端口3001。 然而,当我试图向服务器上的“test”路由发出一个简单的请求时,React代码不会代理这个请求。它将我发送到localhost:3000/test,而不是localhost:3001/

    • 控制器:- 型号:- 我试着让邮递员用以下身体来测试它:-http://localhost:8080/add/score(职位) 我得到了以下错误: