当前位置: 首页 > news >正文

Http请求中的特殊字符

问题

一个 springboot 应用,包含如下 controller

@RestController
public class DemoController {@GetMapping("/get")public ResponseEntity<String> get(@RequestParam(value = "cid2") String cid2)

准备测试数据

String cid2 = "1;MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEoJDsA9HldKEk8i/lbRxS8E13HlCBjg63CrDLF6ieQT+h7K9eRS5jH0VgYXLmWJLOnGLrH1324JaEYHbTmZgpVw==;eWxJY0hrdlBPYVMz;MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpto5kN5HEx/OvVTV2ux08EvneYb+cNx4g9G7ajgH41gBCl7G5JkbaYA7Wf9DxOks3Syu/NJPwhjbOz32L+BfTA==;hcHB3S1D5hgfe5Ar9DUKqW3SeCrvAgeXzt7RldZTh/qWCouFW6NqEZfycxe9Tqi9ehemNc1cMaAtAsC2Ng34hZsEN/cdyqGRcRTbYSpEtdL3GVbyIF5S9hTYD9wcvUMMhsnFIfUMZD0=";

发起请求

String url = UriComponentsBuilder.fromHttpUrl("http://localhost:8080/get").queryParam("cid2", cid2).toUriString();
ResponseEntity<String> forEntity = restTemplate.getForEntity(url, String.class);

发现问题,controller 接收到的数据为

1;MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEoJDsA9HldKEk8i/lbRxS8E13HlCBjg63CrDLF6ieQT h7K9eRS5jH0VgYXLmWJLOnGLrH1324JaEYHbTmZgpVw==;eWxJY0hrdlBPYVMz;MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpto5kN5HEx/OvVTV2ux08EvneYb cNx4g9G7ajgH41gBCl7G5JkbaYA7Wf9DxOks3Syu/NJPwhjbOz32L BfTA==;hcHB3S1D5hgfe5Ar9DUKqW3SeCrvAgeXzt7RldZTh/qWCouFW6NqEZfycxe9Tqi9ehemNc1cMaAtAsC2Ng34hZsEN/cdyqGRcRTbYSpEtdL3GVbyIF5S9hTYD9wcvUMMhsnFIfUMZD0=

对比发现其中的加号变成了空格,而我们希望传递到服务端的是依然是加号。


 

原因分析

根据 URL 编码的规范,空格字符在 URL 查询字符串中通常会被编码为 +。这意味着当发送一个 URL 请求并将 + 作为查询参数时,浏览器和服务器会认为 + 是空格的替代符号。

举个例子:

假设你传递的 URL 是:Example Domain,param=hello+world 中的 + 会被自动解码为一个空格,最终得到的参数值就是 hello world,而不是原始的 hello+world

解决方法

通过 URLEncoder 进行编码

Java 的 URLEncoder 可以将特殊字符(如 ;, /, +, =, %)转义成 URL 编码的格式。例如,空格被编码为 +,而其他特殊字符会转换成以 % 开头的编码形式。

客户端预先编码,得到:

1%3BMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEoJDsA9HldKEk8i%2FlbRxS8E13HlCBjg63CrDLF6ieQT%2Bh7K9eRS5jH0VgYXLmWJLOnGLrH1324JaEYHbTmZgpVw%3D%3D%3BeWxJY0hrdlBPYVMz%3BMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpto5kN5HEx%2FOvVTV2ux08EvneYb%2BcNx4g9G7ajgH41gBCl7G5JkbaYA7Wf9DxOks3Syu%2FNJPwhjbOz32L%2BBfTA%3D%3D%3BhcHB3S1D5hgfe5Ar9DUKqW3SeCrvAgeXzt7RldZTh%2FqWCouFW6NqEZfycxe9Tqi9ehemNc1cMaAtAsC2Ng34hZsEN%2FcdyqGRcRTbYSpEtdL3GVbyIF5S9hTYD9wcvUMMhsnFIfUMZD0%3D

服务端接受到(观察以下数据可以发现%在传输之前再次被编码为%25):

1%253BMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEoJDsA9HldKEk8i%252FlbRxS8E13HlCBjg63CrDLF6ieQT%252Bh7K9eRS5jH0VgYXLmWJLOnGLrH1324JaEYHbTmZgpVw%253D%253D%253BeWxJY0hrdlBPYVMz%253BMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpto5kN5HEx%252FOvVTV2ux08EvneYb%252BcNx4g9G7ajgH41gBCl7G5JkbaYA7Wf9DxOks3Syu%252FNJPwhjbOz32L%252BBfTA%253D%253D%253BhcHB3S1D5hgfe5Ar9DUKqW3SeCrvAgeXzt7RldZTh%252FqWCouFW6NqEZfycxe9Tqi9ehemNc1cMaAtAsC2Ng34hZsEN%252FcdyqGRcRTbYSpEtdL3GVbyIF5S9hTYD9wcvUMMhsnFIfUMZD0%253D

服务端要对接收到的数据 decode 1 次才能得到客户端预先编码后的数据,decode 2 次才能获得我们想要传输的带特殊符号的数据。


 

POST 请求传递特殊字符

POST 请求中,数据被发送到请求体 body,而不是 URL 中,因此特殊字符不会被编码,以下两种方式都可以。

application/json

headers.setContentType(MediaType.APPLICATION_JSON);
Map<String, String> body = new HashMap<>();
body.put("cid2", cid2);RequestEntity<Map> requestEntity = new RequestEntity<>(body,headers,HttpMethod.POST,URI.create("http://localhost:8080/post")
);ResponseEntity<String> exchange = restTemplate.exchange(requestEntity, String.class);

application/x-www-form-urlencoded

headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
formData.add("param", cid2);RequestEntity<MultiValueMap<String, String>> requestEntity = new RequestEntity<>(formData,headers,HttpMethod.POST,URI.create("http://localhost:8080/submit")
);ResponseEntity<String> exchange = restTemplate.exchange(requestEntity, String.class);


 

http://www.lryc.cn/news/592310.html

相关文章:

  • 太阳辐射监测站:洞察太阳能量的科技之眼
  • RabbitMQ—TTL、死信队列、延迟队列
  • k8s:手动创建PV,解决postgis数据库本地永久存储
  • Java Set 集合详解:从基础语法到实战应用,彻底掌握去重与唯一性集合
  • 基于K8s ingress灰度发布配置
  • Docker报错:No address associated with hostname
  • 使用python读取json数据,简单的处理成元组数组
  • 内网部署yum源
  • 美团闪购最新版 mtgsig1.2
  • 从服务实例的元数据中获取配置值 vs 从本地配置文件中获取配置值
  • 4G模块 A7680发送中文短信到手机
  • IT66122替代IT66121-富利威
  • 「源力觉醒 创作者计划」_巅峰对话:文心 4.5 vs. DeepSeek / Qwen 3.0 深度解析(实战优化版)
  • 文件管理-文件控制块和索引节点
  • Java 抽象类与接口深度解析
  • 进阶数据结构:红黑树
  • 可靠消息最终一致性分布式事务解决方案
  • Web3加密货币交易:您需要知道的所有信息
  • MySql:索引,结构
  • 服务器mysql数据的简单备份脚本
  • Ansible + Shell 服务器巡检脚本
  • C#`Array`进阶
  • ChatGPT Agent技术架构探析
  • 力扣面试150(33/150)
  • 解决 IDEA 中 XML 文件的 “URI is not registered” 报错
  • 优先算法——专题九:链表
  • Logback 配置的利器:深入理解<property>与<variable>
  • 深度解析Linux文件I/O三级缓冲体系:用户缓冲区→标准I/O→内核页缓存
  • 【C语言】深入理解柔性数组:特点、使用与优势分析
  • MySQL安装包安装方法