请求参数的乱码问题

请求参数乱码

在使用request.getParameter()取得中文参数时经常会遇到乱码。
产生乱码的根本原因是浏览器端与服务器端的字符编码不一致。

将字符转换成二进制
将二进制转换成字符
浏览器
网络传输
服务器

如果两端使用的转换字符与二进制之间的字符编码不同那么自然会得道乱码。

控制浏览器的字符编码

解决乱码问题的关键在于服务器要告诉浏览器传输参数使用哪种字符编码,而不要让浏览器去自行选择。因为不同的浏览器可能采用不同的字符编码,我们没有办法适应所有的浏览器。
浏览器传参主要有两种方式,在url种直接写参数和在表单中传参两种方式。
因此下面要分开讨论:

表单传参

在服务器响应时可以设置字符编码:

  • 通过设置响应头
response.setCharacterEncoding("utf-8");
  • 使用JSP标签
<%@ page contentType="text/html;charset=utf-8" language="java" %>

这种方式实际上是告诉浏览器,服务器返回的响应是以utf-8编码的,所以浏览器的字符编码也应该使用utf-8。
那这和浏览器传递给服务器的参数有什么关系呢?
这是因为浏览器,在使用表单传参时,默认会使用响应头设置的字符编码。

试一试

<%@ page contentType="text/html;charset=utf-8" language="java" %>
<html>
  <body>
      <form action="hello">
        name:<input name="name" type="text"><br>
        <input type="submit" value="sub">
      </form>
  </body>
</html>

输入框种输入“中文”两个中文字符,当点击提交按钮时,可以打开开发者工具栏查看:

在这里插入图片描述
%E4%B8%AD%E6%96%87正是“中文”两个中文字符的utf-8编码,不信可以试试:

System.out.println(URLDecoder.decode("%E4%B8%AD%E6%96%87","utf-8"));

现在,将utf-8改成gbk

<%@ page contentType="text/html;charset=gbk" language="java" %>
<html>
  <body>
      <form action="hello" enctype="application/x-www-form-urlencoded">
        name:<input name="name" type="text"><br>
        <input type="submit" value="sub">
      </form>
  </body>
</html>

打开控制台
在这里插入图片描述%D6%D0%CE%C4是“中文“的gbk编码,现在可以试一下:

System.out.println(URLDecoder.decode("%D6%D0%CE%C4","gbk"));

注意

  • 浏览器会根据响应头决定表单参数的编码这是所有浏览器都会遵循的,但是有些浏览器比较智能,当你打开控制台时可能不会看到诸如%D6%D0%CE%C4的URL编码,而是看到中文字符,这时因为控制台自动做了转换,但是原理是一样的。
  • 表单传参的编码与method属性是GET还是POST没有关系,如果将上例的表单改成POST只不过参数会出现在消息体中,字符编码任然是一样的

URL直接写入参数

通常用户是不会在URL中直接写入参数的,但是当开发者在写链接是通过URL直接写参数往往不可避免。
但是有一点比较麻烦,浏览器对于URL的请求参数编码是不同的,有的默认是utf-8,有的则不是。
对于这一点,我的结论是永远不要在URL中直接写中文,而是借助于URL编码。

URL编码

URL编码需要用到字符编码,但是它其实和字符编码是两回事。
它们解决的问题是完全不同的:字符编码是为了让计算机能够认识字符,而URL编码是为了过滤一部分字符以实现URL的规范和避免歧义。URL编码使用时要用到字符编码:

System.out.println(URLEncoder.encode("中文","utf-8"));
System.out.println(URLDecoder.decode("%D6%D0%CE%C4","gbk"));

以上分别时URL编码的编码与解码。
现在假设要写一个传递参数中文参数的URL可以这样写:

String url="http:127.0.0.1/helloweb/web?name=";
url+=URLEncoder.encode("中文","utf-8");
System.out.println(url);//http:127.0.0.1/helloweb/web?name=%E4%B8%AD%E6%96%87

这样做的好处就是URL中不会出现任何非ASCLL字符,也符合之前提到的原则,即不要让浏览器决定字符编码。

让服务器的编码与浏览器一致

上面我让浏览器所有的中文字符都使用utf-8,但这只解决了一半,接下来就要让服务器也使用utf-8编码

消息体中的字符编码

可以使用下面的方法让服务器在解析消息体中的字符时使用utf-8编码:

request.setCharacterEncoding("utf-8");

但是需要注意,这种方式只有对消息体中的字符有用,并且这行代码必须出现在读取消息体之前。

URL中的编码

前面使用URL编码来在URL中传递中文字符,服务器在接受到URL时是会自动进行URL解码的,但是URL解码的默认字符是ISO-8859-1,也就是说当"中文"的URL编码传过来时实际上是做了如下操作:

URLDecoder.decode("%E4%B8%AD%E6%96%87","iso-8859-1")

但是之前使用的编码是utf-8所以,一定会有乱码。
为此需要作额外的操作:

byte[] bytes = request.getParameter("name").getBytes("ISO-8859-1");
String name = new String(bytes, "utf-8");

如此一来便大功告成。

猜你喜欢

转载自blog.csdn.net/qq_34935078/article/details/85812926