Http请求传输base64码+号变空格问题
Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法。可查看RFC2045~RFC2049,上面有MIME的详细规范。
Base64编码是从二进制到字符的过程,可用于在HTTP环境下传递较长的标识信息。采用Base64编码具有不可读性,需要解码后才能阅读。
Base64由于以上优点被广泛应用于计算机的各个领域,然而由于输出内容中包括两个以上“符号类”字符(+, /, =),不同的应用场景又分别研制了Base64的各种“变种”。为统一和规范化Base64的输出,Base62x被视为无符号化的改进版本。(by百度百科)
一、简单Http Get请求参数带+示例
Base64中,加号(+)是Base64编码的一部分,如果将+号转变为空格,就会导致解密失败。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript">
function toSend() {
location.href="http://localhost:8080/sendHttp?str=123+456";
}
function toSend2() {
location.href="http://localhost:8080/sendHttp?str="+encodeURIComponent("123+456");
}
</script>
</head>
<body>
<a href="###" onclick="toSend()">模拟请求</a>
<a href="###" onclick="toSend2()">转码模拟请求</a>
</body>
</html>
后台处理:
package com.example.demo.web;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Description Http传输base64编码 加号变空格问题
* @Author jie.zhao
* @Date 2019/9/16 9:58
*/
@RestController
public class HttpBase64Controller {
@GetMapping("/sendHttp")
public String sendHttp(String str){
System.out.println(str);
return str;
}
}
模拟请求:str 参数为:123+456
浏览器地址: http://localhost:8080/sendHttp?str=123+456
后台接收值:123 456
通过模拟请求可以看出,当我们在URL中传递参数中带有+时,会被转换成空格导致后台获取的参数不正确。
解决方案一:
通过 encodeURIComponent 对请求参数进行转码
转码模拟请求: str 参数为:123+456
浏览器地址: http://localhost:8080/sendHttp?str=123%2B456
后台接收值:123+456
解决方案二:
改为form表单提交
二、RestAPI接口Http Get请求参数带+示例
RestTemplate是Spring Web模块提供的一个基于Rest规范提供Http请求的工具。应用中如果需要访问第三方提供的Rest接口,使用RestTemplate操作将非常方便。
配置如下:
package com.example.demo.conf;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* @Description RestTemplateConfig配置
* @Author jie.zhao
* @Date 2019/9/16 11:31
*/
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate( ) {
return new RestTemplate();
}
}
后台处理:
package com.example.demo.web;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
/**
* @Description Http传输base64编码 加号变空格问题
* @Author jie.zhao
* @Date 2019/9/16 9:58
*/
@RestController
public class HttpBase64Controller {
@Autowired
RestTemplate restTemplate;
@GetMapping("/apiSend")
public String apiSend(String str) {
String result = restTemplate.getForObject("http://localhost:8080/apiReceive?str=" + str, String.class);
return result;
}
@GetMapping("/apiReceive")
public String apiReceive(String str) {
System.out.println(str);
return "接收参数" + str;
}
@GetMapping("/apiSend2")
public String apiSend(String str) {
str = URLEncoder.encode(str, "UTF-8");
System.out.println("URL编码:" + str);
String result = restTemplate.getForObject("http://localhost:8080/apiReceive?str=" + str, String.class);
return result;
}
@GetMapping("/apiReceive2")
public String apiReceive(String str) {
str = URLEncoder.encode(str, "UTF-8");
System.out.println("URL编码:" + str);
System.out.println(str);
return "接收参数" + str;
}
}
模拟请求:str 参数为:123+456
浏览器地址: http://localhost:8080/apiSend?str=123+456
后台接收值: 123 456
通过模拟请求可以看出,当我们在请求接口参数中带+,也会被处理成空格导致后台获取的参数不正确。
解决方案一:
参数明确有可能有+号并且不可能有空格的时候,直接replaceAll(" ", "+")。
解决方案二:
对参数进行URL编码,URLEncoder.encode(str)。
模拟请求:str 参数为:123+456
浏览器地址: http://localhost:8080/apiSend?str=123+456
后台接收值: 123+456
注意: 存在的问题 URLEncoder会把空格转成+
模拟请求:str 参数为:123 456
浏览器地址: http://localhost:8080/apiSend?str=123 456
后台接收值: 123+456
三、GET请求会把+号转为空格的原因
1、RFC2396
在RFC2396 列明了";" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | "," 这些字符为保留字符,需要转译后才能出现在uri中。
2.2. Reserved Characters
Many URI include components consisting of or delimited by, certain
special characters. These characters are called "reserved", since
their usage within the URI component is limited to their reserved
purpose. If the data for a URI component would conflict with the
reserved purpose, then the conflicting data must be escaped before
forming the URI.
reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
"$" | ","
The "reserved" syntax class above refers to those characters that are
allowed within a URI, but which may not be allowed within a
particular component of the generic URI syntax; they are used as
delimiters of the components described in Section 3.
2、RFC1866
在RFC1866 规定所有表单的默认编码为application/x-www-form-urlencoded。
RFC 1866 Hypertext Markup Language - 2.0 November 1995
To process a form whose action URL is an HTTP URL and whose method is
`GET', the user agent starts with the action URI and appends a `?'
and the form data set, in `application/x-www-form-urlencoded' format
as above. The user agent then traverses the link to this URI just as
if it were an anchor (see 7.2, "Activation of Hyperlinks").
NOTE - The URL encoding may result in very long URIs, which cause
some historical HTTP server implementations to exhibit defective
behavior. As a result, some HTML forms are written using
`METHOD=POST' even though the form submission has no side-effects.
简单的讲就是form表单提交,from表单提交会默认对参数进行encode操作。浏览器会对form表单的数据进行url编码,把form数据转换成一个字串(name1=value1&name2=value2…),然后把这个字串append到url后面,用?分割,加载这个新的url。
如果表单有加号(+),url编码后会变为%2,这时后接收数据后,对参数解码后转变为+号如果表单有空格,url编码后会变为+,后台接收数据化,解码变为空格。
如果是用的程序写的http请求,需要加一个请求头Content-Type:application/x-www-form-urlencoded,这样就会对参数进行加密操作。
参考文档: