tomcat中的字符集问题,测试以及总结(HTTP请求响应)

时间:2024-01-21 16:03:48

 

HTTP服务器的通常作用可以理解成,接收来自浏览器的请求,读取其中的信息,并返回http格式的数据

其中,浏览器发送的数据主要以三种形式传递,get方式提交的参数,post方式的参数,以及cookie中携带的参数三类

 

而服务器端,生成http返回数据的形式主要有3种

 

 

其中,JSP在本质上与Servlet无异,一般可认为JSP在Servlet的基础上,加上了Html的框架,不过如果把JSP代码中的HTML代码去掉,两者基本就是一个东西了。

 

整个流程中,需要注意到字符集的动作,宏观而言,分为四步:

字符集问题出现在信息从一级流通到另一级的过程中,也就是这4个动作当中。要规避字符集问题,需要了解四个动作中,分别的,其使用的字符集的确认方式。

 

主要包括,a中数据编码采用何种字符集,b中如何确认解析时用的字符集,c中如何确定采用的字符集,d中如何确认解析时所用的字符集

 

以下就这四个问题展开讨论

 

1、浏览器发送数据时,采用哪种字符集?

浏览器发起一个请求,需要通过URL访问

根据形式分为,直接在浏览器中输入URL访问,以及通过链接跳转访问,通过链接跳转访问则包括form表单以及超链接两种形式

 

而无论哪种形式,最终浏览器都会将其包装成HTTP格式进行访问,也即如下格式:

POST /MyTestProject6/Test_Servlet_002 HTTP/1.1
Host: localhost
Connection: keep-alive
Content-Length: 39
Cache-Control: max-age=0
Origin: http://localhost
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: http://localhost/MyTestProject6/Test_003.html
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=1420F43C4B8259D6FCCD46E87B095DB3; _ga=GA1.1.1822121407.1535547634

 

request信息中,并不会指定编码集。

那参数在传递过程中,对中文进行编码的格式如何确定呢?

 

分两种,直接在URL栏中输入的中文,会以浏览器默认的编码集进行编码。

 如此去访问,火狐浏览器的结果是:

chrome浏览器的结果也是:

 

而其他的的访问,也即是由页面生成的URL,其内容的编码格式取决于该页面在编码时使用的字符集

一定程度上,也就是页面中的<meta charset="XXX">标签,该标签标注了该页面的编码格式

(不过会有特例,之后会进行说明)

当页面中<meta charset="XXX">标签缺省时。浏览器会采用默认字符集对页面进行编译,这也是由这个页面所产生的URL在生成request时所采用的字符集。

 

总结:浏览器发送数据时,采用哪种字符集?

1、直接输入URL的,依浏览器(chrome:utf-8,火狐:gbk)

2、页面采用何种字符集编码,则发送数据时采用何种字符集

3、页面未制定字符集时,chrome和火狐都默认使用GKB进行编码

 

 

2、服务器解析浏览器发送的数据时,使用何种字符集?

上文提到,request中并不会携带关于request的内容由哪种字符集信息。

因此,服务器在解析数据时,随缘。。。

比如某个用户在URL中自己手动输入中文参数,可能会影响。

但大多数URL都由服务器自身的页面发出,统一字符集的话,一般不会受到字符集问题的影响。

 

以下,以TOMCAT9为例,阐述如何应对GET请求,POST请求的处理方式。

 

总所周知,一条URL请求,会由浏览器包装成HTTP格式,再发送到服务器,因此服务器接受到的数据是一个数据包,而非单单一个URL字符串。

其中访问路径信息path在第一行的中间,并且以get形式提交的数据显示在了path当中。

tomcat7以上的版本,对于path的内容,会自动用utf-8去解码。其也可以在server.xml中去配置。

而tomcat7以及以下的版本,默认的字符集依然是iso-8859-1。因此需要通过对应的格式去decode。

不过TOMCAT9自动默认UTF-8也有不好的地方,get请求的参数默认就直接UTF-8编码了,也就是无论GBK还是UTF-8发送过来都成了UTF-8。也就无法读取GET里面的内容了

而POST请求,TOMCAT并不会自动解码,而默认的字符集是iso-8859-1,只需要设置其为对应的字符集即可。

 

总结:服务器解析浏览器发送的数据时,使用何种字符集?

可以设置,一般默认iso-8859-1,tomcat7以上get请求默认utf-8

 

3、服务器返回数据时,使用何种字符集?

 服务器返回http数据时,一般有三种方式。

其中servlet中直接在response写入的方式不难得出

 

如果未设置contentType,浏览器会使用默认的iso-8859-1进行解析

如果设置了contentType,比如:

response.setContentType("text/html;charset=utf-8");
response.getWriter().append("测试直接传输一个中文");

 

 则浏览器会使用对应的字符集进行解析。

BUT,需要注意的是,最终传输的数据的字符集需要与此时设置的字符集保持一致。

不一致的情况包括而不限于:

比如上述代码的.java文件字符集是其他的,比如

而代码中设置的字符集为UTF-8,因此最终页面会乱码

这也是JSP跟HTTP页面中需要注意的

 

在HTML页面中,主要通过<meta charset="xxx"> 来控制页面使用的字符集。

<!DOCTYPE html>
<html>
<head>
<meta charset="gbk">
<title>Insert title here</title>
</head>
<body>
    中文
</body>
</html>

 

HTTP/1.1 200
Accept-Ranges: bytes
ETag: W/"300-1536840847318"
Last-Modified: Thu, 13 Sep 2018 12:14:07 GMT
Content-Type: text/html
Content-Length: 300
Date: Thu, 13 Sep 2018 12:14:10 GMT

 

不难看出,在访问HTTP页面时,其response的头中,根本没有标注其所使用的字符集

可以理解成,服务器在响应返回html页面时,并不会对其内容进行解析,而是直接发送过去,因此服务器也不知道该html的字符集

 

而浏览器在接收到response相应之后,也是在读取response的content部分中的meta标签才确定字符集。

HTML文件同样需要注意,最终传输的数据的字符集需要与此时设置的字符集保持一致。

缺省时,chrome和火狐都默认使用gkb编码(应对contentType为text/html)

 

 

在JSP文件中,可以设置的字符集格式文件包括pageEncoding,contentType,以及其html代码中的meta标签。

不过contentType可以缺省,contentType缺省时服务器会根据pageEncoding设置contentType中的charset。

比如:

<%@page pageEncoding="utf-8"%>
这是一个中文
HTTP/1.1 200
Content-Type: text/html;charset=utf-8
Content-Length: 22
Date: Thu, 13 Sep 2018 12:22:49 GMT

 

而如果在已经有pageEncoding的情况下再去设置contentType的charset,后者会覆盖前者,比如:

<%@page contentType="text/html;charset=gbk" pageEncoding="utf-8"%>
这是一个中文
HTTP/1.1 200
Content-Type: text/html;charset=gbk
Content-Length: 16
Date: Thu, 13 Sep 2018 12:24:04 GMT

 

当contentType设置了时,pageEncoding可以缺省,此时会默认使用contentType中设置的字符集作为pageEncoding的字符集。

 

此时依然需要注意,最终传输的数据的字符集需要与此时设置的字符集保持一致。

但此时,如果字符集冲突,其冲突是在JSP的编译阶段,而不是在浏览器上的显示阶段。

 

比如,当我设置了pageEncoding,但是跟.jsp文件采用的字符集不同时,其结果是在编译而成的.java文件中就出现了乱码

 比如

<%@page pageEncoding="utf-8"%>
这是个中文

 

则访问乱码

 

 其.java文件中就已经出现了乱码

  response.setContentType("text/html;charset=utf-8");
      pageContext = _jspxFactory.getPageContext(this, request, response,
                  null, true, 8192, true);
      _jspx_page_context = pageContext;
      application = pageContext.getServletContext();
      config = pageContext.getServletConfig();
      session = pageContext.getSession();
      out = pageContext.getOut();
      _jspx_out = out;

      out.write("\r\n");
      out.write("���Ǹ�����\r\n");

 

 

当pageEncoding和contentType都缺省时,JSP编译器会很晕。。然后用iso-8859-1编码

总之!!就是不用meta里面设置的字符集。。。

<%@page%>
<!DOCTYPE html>
<html>
<head>
<meta charset="gbk" />
<title>Insert title here</title>
</head>
<body>我是个中文
</body>
</html>

 

HTTP/1.1 200
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 136
Date: Thu, 13 Sep 2018 12:34:10 GMT

 

 

总结:服务器返回数据时,使用何种字符集?

1、servlet端需要设置contentType,注意与代码的编码文件格式保持一致,缺省时浏览器使用iso-8859-1。

2、html文件需要设置<meta charset>,注意与html文件的编码格式保持一致,缺省时浏览器使用gbk。

3、jsp文件需要设置contentType或pageEncoding,注意与jsp文件的编码格式保持一致,缺省时浏览器使用gbk,但JSP编译器会通过iso-8859-1去编译。

 

 

4、浏览器解析数据时,采用何种字符集

 依照上文

浏览器在解析时使用的字符集,依照response的head中的参数。

总结:

1、当缺省时,若返回的contentType为html/gbk,则火狐和chrome都会使用GBK编码

2、若contentType缺省,则会使用iso-8859-1编码。