noteless 头像

javaweb请求编码 url编码 响应编码 乱码问题 post编码 get请求编码 中文乱码问题 GET POST参数乱码问题 url乱码问题 get post请求乱码 字符编码

 乱码是一个经常出现的问题
请求中,参数传递的过程中也是经常出现乱码的问题
本文主要整理了请求乱码中的问题以及解决思路
 
先要理解一个概念前提:
编码就是把图形变成数值码所以说:
图形的字符  ---->  字节数组  是编码
字节数组-------->图形的字符 是解码
 

为什么会乱码?

计算机数据只能是二进制的
数值类型的数据转换成二进制很简单,
但字符类型如何转换成二进制呢?这就需要使用字符编码!
在编码表中,每个字符都有对应的编码,编码是整数,最终在计算机中存储的是字符的编码
而不是字符本身(因为计算机数据都是二进制数值,所以字符本身是无法存储的)。
 
假如说两种编码
红框1    橘色框 2 ,不用较真数值是多少,符号是什么,只为表达概念
每种编码方式内部,字符和数值是一 一对应的
但是如果使用A------>65进行编码 
然后使用      65------>$ 另外一种解码方式解读,显然A就变成了$,这不就是乱码了么
不同的编码方式不同,同一个字符的二进制也基本是不同的,如果没有正确的进行解读,那么就会出现乱码问题
发起请求时,不管是什么字符,计算机都不认识,必须编码转换为数值.
接收到请求的地方想要使用,就必须在编码成为字符
乱码的根本在于 编码和解码方式的前后不一致
 

 
如何解决乱码问题,也就是正确编码的问题
请求响应的编码问题

1.直接在地址栏中给出中文

请求数据是由客户端浏览器发送服务器的,请求数据的编码是由浏览器决定的。
例如在浏览器地址栏中给出:http://localhost:8080/servlet/AServlet?name=张三,那么其中“张三”是什么编码的呢?
不同浏览器使用不同的编码,所以这是不确定的!
Chrome:使用UTF-8;
IE:使用GB2312;
FireFox:使用GB2312;
 
(这几个说的不一定对,反正重点是要知道,不同的浏览器,直接地址栏输入的参数的字符编码是不固定的,也说不定未来或许会统一)

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请求解读编码

 

当客户端通过GET请求发送数据给服务器时
使用request.getParameter()获取的数据是被服务器误认为ISO-8859-1编码的
也就是说客户端发送过来的数据无论是UTF-8还是GBK,服务器都认为是ISO-8859-1  
tomcat8以后默认编码格式是utf-8;7之前的都是iso8859-1
 

是否需要在使用request.getParameter()获取数据后,再转发成正确的编码
要看你实际使用的tomcat 版本
例如客户端以UTF-8发送的数据,使用tomcat7 以及之前的版本
需要使用如下转码方式:

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"));
}
 
 
 
 
posted @ 2018-08-08 14:23  noteless  阅读(1669)  评论(0编辑  收藏  举报