1. 浏览器编码
浏览器是通过http协议与服务器交互,http的请求或响应报文格式如下:
(1)start line
(2)headers
(3)body
其中按规定,(1)、(2)必须是ASCII码的字符,因此非ASCII码的需要转换成ASCII码,分别介绍如下:
1)start line(起始行):其包含请求方法(post、get等)、URL、版本,在startline中需要注意的url,以如下url为例
例:http://localhost:8080/servletTest/中文路径?name=中文参数
其中:http://localhost:8080/servletTest/中文路径为pathInfo(路径信息)
name=中文参数为queryString(请求参数),为满足startline全为ASCII字符,因此需要将pathInfo、queryString中中文字符先编码成字节数组,然后以16进制形式展现,并在没两个字符前加上%(即urlcode)
对于pathinfo、queryString的编码规则如下:
a. pathInfo的编码受浏览器的编码格式控制(chrome浏览器默认编码格式为utf-8)
b.queryString的编码分不同情况:在浏览器中直接输入,受浏览器的默认编码格式控制(注:页面内通过<a>等跳转的也属于浏览器直接输入这种情况) 、在页面内的get请求受页面控制<meta charset="gbk">
2)headers:头信息,如Accept-Charset等,其中可能会出现中文的有
a. Content-disposition:这个是用于控制文件采用何种方式、默认文件名。具体格式为
disposition-type;disposition-parm,其中disposition-type有两种分别为inline(在浏览器中直接打开)和 attachment(以附件的形式,提供下载),其中disposition-parm可为filename={filename},此时filename根据需求可能为中文,解决乱码问题的方法是对其进行url编码即可
b.Cookie:其中也可能存在中文乱码,因此需要url编码
3)body
body里是什么内容,如果是字符采用什么编码,如果是图像又采用什么格式,所有这些都是由headers中Content-Type里规定的。
常见的Content-Type如下:
- text/html : HTML格式
- text/plain :纯文本格式
- text/xml : XML格式
- image/gif :gif图片格式
- image/jpeg :jpg图片格式
- image/png:png图片格式
- application/xml : XML数据格式
- application/json : JSON数据格式
- application/pdf :pdf格式
- application/msword : Word文档格式
- application/octet-stream : 二进制流数据(如常见的文件下载)
- application/x-www-form-urlencoded : <form encType=””>中默认的encType,form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)
- multipart/form-data : 需要在表单中进行文件上传时,就需要使用该格式(上传文件时使用)
如Content-Type: text/html; charset=UTF-8,表示body里的内容是html文件,采用UTF-8编码
Content-Type: application/x-www-form-urlencoded:POST常用的消息类型,它表明body里放的是表单数据,采用的编码为urlencoded。首先,这种格式的body内容必须为ASCII码,除了格式化字符自身外,其他字符必须限定于ASCII的unreserved子集。举例来说,这种body的格式为name1=value1&name2=value2&name3=&name4=value4,name1,name2,name3,name4为变量名,value1,value2,value3,value4为变量的值,=和&为格式化字符,这里要求name1,name2,name3,name4,value1,value2,value4的编码必须为ASCII的UnReserved子集
2. 服务器解码
1)URL的URI部分进行解码的字符集是在connector的<Connector URIEncoding-"UTF-8">中定义的,如果没有定义,那么将以默认编码IS0-8859-1解析
ps:所以有中文URL时最好把URIEncoding设置成UTF-8编码
2)QueryString的解码字符集要么是Header中ContentType定义的Charset,要么是默认的ISO-8859-1,要使用ContentType中定义的编码,就要将connector的<Connector URIEncoding-"UTF-83useBodyEncodingForURI-"true"/>中的useBodyEncodingForURI设置为true
3)InputStreamReader类就是关联字节到字符的桥梁,它负责在I/O过程中处理读取字节到字符的转换,需要指定Charset,如果没有则将使用本地环境中的默认字符集,如在中文环境中将使用GBK编码
4)Charset类取代。Charset提供encode与decode,分别对应char[](即String)到byte[]的编码解码
3. 问题定位
1)一个汉字变成了一个问号:将中文和中文符号经过不支持中文的ISO-8859-1编码后,所有字符变成了“?”