发送请求时,浏览器内部如何编码

本文中示例,在fixfore浏览器下测试通过。

总结

URI路径部分,不论是在浏览器地址栏中直接输入,还是在<form>标签的action属性中指定,其中文部分都会使用UTF-8编码;
URI查询参数部分,有所不同。在浏览器地址栏中直接输入时,会使用UTF-8编码;在标签的action属性中指定时,取决于其content-type中指定的编码格式。
POST请求主体部分,取决于其content-type中指定的编码格式。

服务器接收

下面进行具体测试。

浏览器地址栏中的中文

直接在浏览器地址栏中输入含中文网址,比如

http://localhost:8080/hello-user/greeting/山东?user=山东

时,浏览器请求头分析如下:
请求头
也就是说,对于网址中的非ASCII字符先使用UTF-8编码,并以16进制字符串表示,然后再在每个字节前加上%。比如,中文字符串山东的十六进制形式的UTF-8编码是E5B1B1E4B89C

http://localhost:8080/hello-user/greeting/%E5%B1%B1%E4%B8%9C?user=%E5%B1%B1%E4%B8%9C

form表单POST请求中的中文

比如,

<form action="greeting/山东?user=山东" method="POST">
	Enter your name:<br>
	<input type="text" name="user" value="山东"><br>
	<input type="submit" value="Submit">
</form>
content-type指定ISO-8859-1编码时

浏览器发送请求前,content-type指定编码方式是ISO-8859-1,请求头如下:
浏览器发送请求前,请求头浏览器发送请求后,请求头如下:
浏览器发送请求后,请求头如下:请求主体
也就是说,
对于网址中的URI路径部分,处理方式与直接在浏览器地址栏中输入网址的处理方式一样。
对于网址中的URI查询参数部分,先对其中的非ISO-8859-1字符转成用&#...;包裹的十进制形式的unicode内码点,比如中文字符串山东,会转成&#23665;&#19996;,再将该内码点形式中的&#;以16进制字符串表示,然后再在每个字节前加上%,比如,%26%2323665%3B%26%2319996%3B
对于请求主体部分,编码方式与URI查询参数部分一致。

content-type指定GBK编码时

浏览器发送请求前,content-type指定编码方式是GBK,请求头如下:
在这里插入图片描述发送POST请求后,请求头如下:
在这里插入图片描述在这里插入图片描述
也就是说,
对于网址中的URI路径部分,处理方式与直接在浏览器地址栏中输入网址的处理方式一样。
对于网址中的URI查询参数部分,先使用GBK编码,并以16进制字符串表示,然后再在每个字节前加上%。比如,中文字符串山东的十六进制形式的GBK编码是C9BDB6AB
对于请求主体部分,编码方式与URI查询参数部分一致。

content-type指定UTF-8编码时

浏览器发送请求前,content-type指定编码方式是UTF-8,请求头如下:
在这里插入图片描述发送POST请求后,请求头如下:
在这里插入图片描述在这里插入图片描述
也就是说,
对于网址中的URI路径部分,URI查询参数部分,以及请求主体部分,三者的处理方式都与直接在浏览器地址栏中输入网址的处理方式一样。

form表单GET请求中的中文

<form>表单POST请求中的中文处理方式一致。不再赘述。

附录

获得中文的指定编码格式的十六进制形式
  1. 引入jar包
<dependency>
   	<groupId>ru.d-shap</groupId>
   	<artifactId>hex</artifactId>
   	<version>1.2</version>
</dependency>
  1. 测试使用
String original = "山东";
System.out.println(HexHelper.toHex(original.getBytes("GB2312"), true));
System.out.println(HexHelper.toHex(original.getBytes("GBK"), true));
System.out.println(HexHelper.toHex(original.getBytes("UTF-8"), true));
System.out.println(HexHelper.toHex(original.getBytes("UTF-16"), true));
System.out.println(HexHelper.toHex(original.getBytes("UTF-32"), true));

第一个参数是字符串在不同编码格式下对应的字节数组,第二个参数用来选择是否将十六进制字符串转成大写形式。
结果如下,

C9BDB6AB	<-GB2312
C9BDB6AB	<-GBK
E5B1B1E4B89C	<-UTF-8
FEFF5C714E1C	<-UTF-16
00005C7100004E1C	<-UTF-32

原理很简单,自己查jar包源码,不再赘述。

中文字符与其unicode内码点相互转换
  1. 引入jar包
<dependency>
   <groupId>org.apache.commons</groupId>
   <artifactId>commons-lang3</artifactId>
   <version>3.9</version>
</dependency>
  1. 字符转\uxxx形式十六进制内码点字符串
// 字符转`\uxxx`形式内码点字符串
System.out.println(CharUtils.unicodeEscaped('山'));

结果是,\u5c71\u4e1c
3. 字符串转int形式十进制内码点数组

int[] codePoints = StringUtils.toCodePoints("山东");
for (int i : codePoints) {
	System.out.println(i);
}

结果是,2366519996
4. 内码点转字符

// 直接转
char s = (char)23665;
System.out.println(s);
char d = '\u4e1c';
System.out.println(d);

// 字符串转(有时候原始数据是字符串形式)
int s10 = Integer.parseInt("23665");
System.out.println((char)s10);
String d2 = "\u4e1c"
System.out.println(d2 );//也可以直接输出
模拟浏览器中请求体内中文参数ISO-8859-1时编码

山东&#23665;&#19996;,再转%26%2323665%3B%26%2319996%3B

private static String String2Unicode(String str) throws UnsupportedEncodingException {
	
	StringBuilder sb = new StringBuilder();
	for (int i : StringUtils.toCodePoints(str)) {
		sb.append("&#").append(i).append(";");
	}
	
	String encode = URLEncoder.encode(sb.toString(), "ISO-8859-1");
	System.out.println(str+ " : " + sb + " : " + encode);
	return encode;
}

%26%2323665%3B%26%2319996%3B&#23665;&#19996;,再转山东

private static String unicode2String(String str) throws UnsupportedEncodingException {
	String decode = URLDecoder.decode(str, "ISO-8859-1");
	
	StringBuilder sb = new StringBuilder();
	for (String s : StringUtils.split(decode, ";")) {
		int i = Integer.parseInt(StringUtils.substring(s, 2));
		sb.append((char)i);
	}
	
	System.out.println(str + " : " + decode + " : " + sb);
	return sb.toString();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值