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,這樣就會對參數進行加密操作。
參考文檔: