关于SpringBoot中接收application/x-www-form-urlencoded;charset=GB2312乱码问题详解
1.背景
公司最近在对接一个上游客户,客户接口传递过来的数据是一个application/x-www-form-urlencoded;charset=GB2312类型,其中字段中存在部分中文如下图所示。
公司的项目为UTF-8编码,对于GBK编码传递过来的数据出现�ɹ�乱情况表示也很正常,但是后续无论怎么加解密,都无法完整解决乱码问题,内心是无比的烦躁。
根据下面的编码错误格式可知,由于之前是GBK编码的中文字符串,被SpringBoot使用默认UTF-8的形式进行了转码,从而出现乱码。
解决办法: server.servlet.encoding=false,解除SpringBoot中强制转换UTF-8。
server:
port: 11187
servlet:
context-path: /charge-mob
encoding:
force: false
2.深入分析
x-www-form-urlencoded传递原理
x-www-form-urlencoded在使用POST请求发送数据时,会将目标内容进行URLEncoder之后塞进请求体里。
在获取原始的@RequestBody时发现,两者的Orderinfo内容存在不一致的情况。
- 原始为:%B3%C9%B9%A6
- 输出字符串:%EF%BF%BD%C9%B9%EF%BF%BD
思考:为啥使用一手的@RequestBody会得到不一致的请求内容。
本人打算从URL加解密入手来复现上述各种乱码与不一致情况,使用以下代码进行测试:
System.out.println("=========================================");
// 原始的GBK编码的URL参数
String original = "%B3%C9%B9%A6";
System.out.println("原始URL编码的GBK:"+original);
// 使用GBK解码
String decodedGbk = URLDecoder.decode(original, "GBK");
System.out.println("Decoded with GBK: " + decodedGbk);
// 将GBK解码后的字符串再编码为UTF-8
String reEncodedUtf8 = URLEncoder.encode(decodedGbk, "UTF-8");
System.out.println("Re-encoded with UTF-8: " + reEncodedUtf8);
// 使用错误的UTF-8解码(模拟乱码情况)
String wronglyDecodedUtf8 = URLDecoder.decode(original, "UTF-8");
System.out.println("Wrongly decoded with UTF-8: " + wronglyDecodedUtf8);
// 将错误解码后的字符串再编码为UTF-8(可能产生乱码)
String wronglyReEncodedUtf8 = URLEncoder.encode(wronglyDecodedUtf8, "UTF-8");
System.out.println("Wrongly re-encoded with UTF-8: " + wronglyReEncodedUtf8);
得到了下述结果:
- 当使用URLDecoder.decode(original, “UTF-8”);进行解密时会出现�ɹ�,符合上述乱码条件。
- 当对�ɹ�在此进行URLEncoder.encode(wronglyDecodedUtf8, “UTF-8”)编码时会出现@RequestBody中%EF%BF%BD%C9%B9%EF%BF%BD的编码情况。故原始字符串再经过一次URLEncoder后再经历了一次URLDecoder才被字符串输出。