乱码是一个常常出现的问题
请求中,参数传递的过程当中也是常常出现乱码的问题
本文主要整理了请求乱码中的问题以及解决思路
先要理解一个概念前提:
编码就是把图形变成数值码因此说:
图形的字符 ----> 字节数组 是编码
字节数组-------->图形的字符 是解码
为何会乱码?
计算机数据只能是二进制的
数值类型的数据转换成二进制很简单,
但字符类型如何转换成二进制呢?这就须要使用字符编码!
在编码表中,每一个字符都有对应的编码,编码是整数,最终在计算机中存储的是字符的编码
而不是字符自己(由于计算机数据都是二进制数值,因此字符自己是没法存储的)。
假如说两种编码
红框1 橘色框 2 ,不用较真数值是多少,符号是什么,只为表达概念
每种编码方式内部,字符和数值是一 一对应的
可是若是使用A------>65进行编码
而后使用 65------>$ 另一种解码方式解读,显然A就变成了$,这不就是乱码了么
不一样的编码方式不一样,同一个字符的二进制也基本是不一样的,若是没有正确的进行解读,那么就会出现乱码问题
发起请求时,不论是什么字符,计算机都不认识,必须编码转换为数值.
接收到请求的地方想要使用,就必须在编码成为字符
如何解决乱码问题,也就是正确编码的问题
请求响应的编码问题
1.直接在地址栏中给出中文
请求数据是由客户端浏览器发送服务器的,请求数据的编码是由浏览器决定的。
例如在浏览器地址栏中给出:http://localhost:8080/servlet/AServlet?name=张三,那么其中“张三”是什么编码的呢?
不一样浏览器使用不一样的编码,因此这是不肯定的!
Chrome:使用UTF-8;
(这几个说的不必定对,反正重点是要知道,不一样的浏览器,直接地址栏输入的参数的字符编码是不固定的,也说不定将来或许会统一)
2. 响应编码
当使用response.getWriter()来向客户端发送字符数据时,若是在以前没有设置编码,那么默认使用iso,由于iso不支持中文,必定乱码
response.getWriter().println("ServletA");
response.getWriter().println("你好");
在使用response.getWriter()以前
可使用response.setCharacterEncoding()来设置字符流的编码为gbk或utf-8
固然咱们一般会选择utf-8
response.setCharacterEncoding("utf-8");
这样使用response.getWriter()发送的字符就是使用utf-8编码的。但仍是会出现乱码!
由于浏览器并不知道服务器发送过来的是什么编码的数据!这时浏览器通常会使用gbk来解码,因此乱码!
因此须要设置响应的编码,以及通知浏览器应该使用何种编码方式去解读
在使用response.getWriter()以前
可使用
response.setHeader("Content-type","text/html;charset=utf-8")
来设置响应头,通知浏览器服务器这边使用的是utf-8编码
并且在调用setHeader()后
还会自动执行setCharacterEncding()方法。
这样浏览器会使用utf-8解码,因此就不会乱码了!
response.setHeader("Content-type","text/html;charset=utf-8");
response.getWriter().println("ServletA");
response.getWriter().println("你好");
setHeader("Content-Type", "text/html;charset=utf-8")的快捷方法是:
response.setContentType("text/html;charset=utf-8);
总结:输出响应,想要不乱码
只须要在使用getWriter()方法前:
response.setContentType("text/html;charset=utf-8);
若是是静态页面中,使用<meta>来设置content-type响应头,例如:
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
补充说明:
UTF-8 中 三个字节表示一个中文
E4BDA0=你 E5A5BD=好
发送的时候是UTF-8 也就是发送的 E4BDA0E5A5BD
GBK中两个字节表示一个中文
也就是
E4BD A0E5 A5BD
查表可得:
3.在页面中发出请求
一般向服务器发送请求数据都须要先请求一个页面,而后用户在页面中输入数据。
页面中有超连接和表单,经过超连接和表单就能够向服务器发送数据了。
用户在页面中输入的数据是由页面自己的编码决定的
又由于页面是服务器发送到客户端浏览器的,因此这个页面自己的编码又由服务器响应决定
|
|
服务器返回当前页面的响应时,设置响应头content-type,指定当前页面的编码为utf-8
若是设置了那么能够经过浏览器查看响应信息看到
若是是
Content-Type:text/html; 而没有后面的charset=utf-8
能够看下输出的响应页面上是否有这一句,也是同样的
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
归根结底是看响应中是否有 Content-type utf-8 的相关信息 有了charset的信息,就按照他来
4.GET请求解读编码
使用request.getParameter()获取的数据是被服务器误认为ISO-8859-1编码的
也就是说客户端发送过来的数据不管是UTF-8仍是GBK,服务器都认为是ISO-8859-1
tomcat8之后默认编码格式是utf-8;7以前的都是iso8859-1 |
是否须要在使用request.getParameter()获取数据后,再转发成正确的编码
要看你实际使用的tomcat 版本
例如客户端以UTF-8发送的数据,使用tomcat7 以及以前的版本
须要使用以下转码方式:html
String name = request.getParameter(“name”);
name = new String(name.getBytes(“iso-8859-1”), “utf-8”);
重点是要理解逻辑:
tomcat 默认的使用某种编码对传递过来的数据进行了解码
若是说正好是咱们传递过来的,那么不须要作处理
若是不是,就须要按照他解码的方式,从新编码成字符数组,在使用字节数组 按照编码规则从新解码为字符串
(字符到字节数组是编码 字节数组到字符是解码)
示例:
在utf8页面上 get请求 http://127.0.0.1:8080/servlet/ServletA?name=张三
Servlet中
String name = request.getParameter("name");
System.out.println("request.getParameter(\"name\"): "+name);
name = new String(name.getBytes("iso-8859-1"), "utf-8");
System.out.println("new String(name.getBytes(\"iso-8859-1\"), \"utf-8\"): "+name);
页面是utf8 天然请求是utf8编码规则
tomcat8 默认utf8 解码
tomcat7 默认iso
固然也是能够修改Server.xml中设置URIEncoding的值为UTF-8
可是不建议这么作,代码不能依赖tomcat的设置,严重破坏可移植性
5.POST请求解读编码
当客户端经过POST请求发送数据给服务器时,能够在使用request.getParameter()获取请求参数以前
先经过request.setCharacterEncoding()来指定编码,而后再使用reuqest.getParameter()方法来获取请求参数
也就是说,若是是POST请求,服务器能够指定编码!
但若是没有指定编码,那么仍旧也仍是使用默认的来解读
request.setCharacterEncoding(“utf-8”);
String name = request.getParameter(“name”);
6. URL编码
POST表单提交的类型:
Content-Type: application/x-www-form-urlencoded |
- 首先,Content-Type 被指定为 application/x-www-form-urlencoded;
- 其次,提交的数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL 转码。
- 大部分服务端语言都对这种方式有很好的支持。
其实就是把中文转换成%后面跟随两位的16进制。
在客户端和服务器之间传递中文时须要把它转换成网络适合的方式
不是字符编码,客户端与服务器之间传递参数用的一种方式 |
URL编码须要先指定一种字符编码,把字符串解码后,获得byte[],而后把小于0的字节+256,再转换成16进制。前面再添加一个%。
* POST请求默认就使用URL编码!tomcat会自动使用URL解码!
* URL编码:String username = URLEncoder.encode(username, "utf-8");
* URL解码:String username = URLDecoder.decode(username, "utf-8");
|
这种场景下,编码和解码都是自动的,不须要手动干预
浏览器中显示的"张三"
新建一个测试类 main方法中执行打印结果同样
public static void main(String[] args) throws UnsupportedEncodingException {
String s= "张三";
System.out.println(URLEncoder.encode(s,"UTF-8"));
}