Http请求和响应的编码问题

前言:

今天来谈谈Tomcat服务器和网页之间编码和解码之间的关系。
关于URL编码的问题可以看
链接:廖雪峰
修正:百度现在编码也是UTF-8

关于编码之间的转换问题可以看
链接:编码转换问题

浏览器端的编码:

默认解码是GB2312
影响form提交数据的编码的因素包括:form的accept-charset属性、html文档的编码方案即document.charset。其中,form的accept-charset是否能够有效,依赖具体浏览器的实现,有些浏览器并不支持,如IE。文档编码方案可以通过document.charset来修改。

浏览器端的解码:

默认解码是GB2312
这个是国情所致,不管是windows还是linux都是如此,除非自己设置。

通常来说,浏览器会先按照Content-Type的编码设置来解析文本,然后在解析过程中发现charset设置,再更换编码重新读取。若Content-Type没有设置编码,或者说这个HTML文件根本就不是走的HTTP协议,浏览器通常会猜测编码来解析文本,然后发现charset设置再更换编码读取。

来做个测试:
写了一个网页 没有声明meta等编码格式,但是文本是UTF-8编写的。
这时候浏览器打开该网页,发现乱码问题。
然后后台接受数据

request.setCharacterEncoding("GBK"); //或者GB2312
System.out.println(request.getParameter("name"));

输出结果不是乱码。
替换:

request.setCharacterEncoding("UTF-8"); //或者不写
System.out.println(request.getParameter("name"));

就根据request默认编码格式 iso-8859-1出现乱码。

浏览器的数据体解码方案依赖返回信息。
a) 浏览器首先从返回头header中查找编码方案标注(Content-Type),举个栗子:

response.setHeader  
("content-type", "text/html;charset=utf-8");  

b)如果没有标注,在得知返回内容为html内容的话,将从head的meta标签中读取,举个栗子:

 <meta http-equiv=Content-Type  
 content="text/html;charset=utf-8">

c)如果还没找到,浏览器就不知道如何解码,会消极的选择一种解码方案。默认解码是GB2312

在理论上,推荐html文档在meta中声明编码,且编码的声明一定要在文件开始的1024字节内完成,所以最好在head标签开始时立即声明。

总结:服务器的编码解码主要是看:

1. 头header中meta的编码方案
2. html文档的编码方案 
3. form的accept-charset编码方案

只要页面声明了charset什么格式,那么编码和解码就什么格式。


服务器端的编码:

中文版的浏览器一般会默认的使用GBK,通过设置浏览器也可以使用UTF-8,可能不同的用户就有不同的浏览器设置,也就造成不同的编码方式,所以很多网站的做法都是先把url里面的中文或特殊字符用 javascript做URL encode,然后再拼接url提交数据

Tomcat8以上默认是UTF-8

所以编码默认是UTF-8

所以getBytes()是默认采用UTF-8 还可以选择编码格式。
举个栗子:

response.getOutputStream().write  
("22这d是一个字节输出".getBytes("GBK"));

分析:

response存放的格式是GBK 浏览器默认是GBK打开正常显示
如果改为.getBytes()则为UTF-8 浏览器打开就会乱码

总结:
HttpServletResponse跟HttpServletRequest默认编码不一样
HttpServletResponse默认编码不是iso-8859-1,而是取决于直接存入的编码格式,意思取决于getBytes
默认应该是在doGet方法中,因为浏览器默认是以Get方式访问Servlet。

设置浏览器解码格式

response.setHeader("Content-type", "text/html;  
charset=UTF-8");

如果修改的话 可以看这一篇 很详细:

https://blog.csdn.net/jiangwei0910410003/article/details/22886847

修正:

response.getWriter().write();的默认编码是UTF-8
response.getOutputStream().write(string.getBytes());  
默认编码格式是UTF-8

完整栗子:

response.setHeader("Content-type", "text/html;charset=UTF-8");
response.getOutputStream().write("22这是一个字节输出".getBytes());
response.getWriter().write("哈哈对是");

输出:

22这是一个字节输出

总结:
1. getOutputStreamgetWriter这两个方法互相排斥,调用了其中的任何一个方法后,就不能再调用另一方法。
2. getOutputStream()和getWriter()可以层叠使用。
3. Serlvet的service方法结束后,Servlet引擎将检查getWriter或getOutputStream方法返回的输出流对象是否已经调用过close方法,如果没有,Servlet引擎将调用close方法关闭该输出流对象。

服务器端的解码:

这块是我认为最难理解的。……
可以参考这篇:

https://blog.csdn.net/qq_38409944/article/details/80633743

  1. Tomcat8以上版本默认编码格式是UTF-8
  2. HttpServletRequest和HttpServletResponse容器默认编码格式是iso-8859-1

Get和Post解码格式:
request容器保存的是浏览器的数据,一般是UTF-8格式。
request的方法如:getParameter解码格式会根据Get和Post来设置解码格式。

1. Get默认解码格式是Tomcat8编码格式。所以URL解码是UTF-8,
覆盖掉了request容器解码格式
2. Post默认解码格式是request编码格式。与Tomcat8编码格式无关

从浏览器发起的访问方式有三种:

request乱码指的是:浏览器向服务器发送的请求参数中包含中文字符,
服务器获取到的请求参数的值是乱码;

一般默认浏览器传递过来的数据是UTF-8格式。
对于传输的数据 有两种方式传输 一种是Post一种是Get 对于不同方式传递过来的数据。解码方式又是不同的。

Get是放在URL参数
Post是放在实体内容里 

但都可以通过HttpServletRequest request来解码

在地址栏直接输入URL访问、
点击页面中的超链接访问、
提交表单访问。

第一种访问方式浏览器默认将参数按照utf-8进行编码,
后面两种访问方式浏览器将参数按照当前页面的显示编码进行编码。所以对于request乱码,只需要在服务器端设置相应的解码格式即可。由于访问方式不同,浏览器对参数的编码格式也不同,为了方便处理,通过超链接和表单的访问也规定必须是utf-8格式,即显示当前页面的编码也要使用utf-8,这样浏览器将统一使用utf-8对参数进行编码。

在服务器端,通过request.setCharacterEncoding(“utf-8”)即可设置服务器response容器的编码为utf-8(默认是ISO-8859-1),
但是它只对请求体里面的参数有效;
如果参数跟在请求行中的uri后边,它就无能为力了。因此请求方式不同,解决乱码的方案也不同。

通过修改server.xml指定服务器对get和post统一按照utf-8解码,要求tomcat管理下的所有web应用都要使用utf-8编码
结论: 约定很重要,网站一般采用UTF-8作为默认编码。如果不是特殊需求,不要变换成其他编码。

总结:get请求建议尽量不带中文参数

https://www.cnblogs.com/caowei/p/2013-12-11_request-response.html
https://blog.csdn.net/jiangwei0910410003/article/details/22886847
https://m.imooc.com/article/18897
http://blog.51cto.com/yuehaoyisheng/1324709
“`

你可能感兴趣的:(JAVA,Web基础)