码迷,mamicode.com
首页 > 其他好文 > 详细

response.setContentType response.setCharacterEncoding response.setLocale实验总结

时间:2015-05-07 16:45:58      阅读:370      评论:0      收藏:0      [点我收藏+]

标签:response   charset   contentype   setlocale   charactere   

前几天有个人问我这几个到底什么区别,表示自己也不是很懂,找了很多资料,说的模棱两可的,还是自己动手实践吧。

1.setContentLength(int len):设置响应消息的实体内容的大小,单位为字节,对应于Http协议中的Content-Length响应头字段。
一般我们写的servlet不用设置Content-Length的头字段,因为服务器在向客户端输出的时候会自己设置该头字段的值,或者选择chunked传输编码方式。
如:

protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException{
    response.setContentType( "text/html;charset=gb2312");
    PrintWriter out = response.getWriter();
    out.println( "<a href=‘www.baidu.com‘>百度</a>" );
}

在firefox中接收到响应:
技术分享
在servlet中并没有设置Content-Length的值,但是在响应消息头中出现了Content-Length,说明tomcat服务器自动帮我们设置了该值。<a href=‘www.baidu.com‘>百度</a>这段文本总共有34个字节(gb2312/gbk格式的中文字符每个字占两个字节,所以值为34)

现在我们手动将Content-Type的值设为35,代码改为:

protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException{
    response.setContentType( "text/html;charset=gb2312");
    response.setContentLength(35);
    PrintWriter out = response.getWriter();
    out.println( "<a href=‘www.baidu.com‘>百度</a>" );
}

接收到响应消息为:
技术分享
但是,返回的实体内容长度为34,我们手动设置为错误的数字35,浏览器会有什么反应呢:
技术分享
经过多个浏览器测试,当Content-Length设置错误的时候,浏览器会一直处于“正在连接”状态,这个状态一般持续7、8秒钟,然后将正确显示出返回内容。也就是说,如果返回的是纯文本内容,浏览器会试图解析该文本内容,是会显示出正确结果的,只是反应时间很慢。但是如果你的网页需要输出图片等二进制流(比如后台生成验证码图片),这个时候如果Content-Length设置错误的话,将导致显示错误。
所以我们最好将设置Content-Length值的工作交给服务器来完成吧。

2.setContentType:对应于Http协议中的Content-Type头字段
(1)设置MIME类型
servlet代码如下:

protected void doGet(HttpServletRequest req, HttpServletResponse response) throwsServletException, IOException{
    response.setContentType( "text/plain" );
    PrintWriter out = response.getWriter();
    out.println( "<a href=‘www.baidu.com‘>test</a>" );
}

网页显示内容:
技术分享
我们看到浏览器只是将响应内容当成文本来处理,现在将代码改为:

response.setContentType( "text/html" );

技术分享
这个时候浏览器将返回内容当成html来解析了。
简单来说,该方法告诉浏览器我要返回的内容的MIME类型,可以这样理解。如果是文本,就直接显示,如果是html文本,就解析再显示,如果是图片,就调用浏览器的图片控件解析图片,视频就调用浏览器的视频控件解析。如果你不告诉浏览器你传过来的东西是什么,那么浏览器就不知道怎么解析,这个字段我们一定要加上。
(2)设置字符编码
我们将servlet代码改为:

protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException{
    response.setContentType( "text/html");
    PrintWriter out = response.getWriter();
    out.println( "<a href=‘www.baidu.com‘>百度</a>" );
}

浏览器显示结果为:
技术分享
为什么会这样呢?原来如果你不在Content-Type中设置字符集编码,那么tomcat默认使用ISO8859-1,这个字符集中是没有中文的,所以会出现问号,表示找不到该字符。

将代码改为:

response.setContentType( "text/html;charset=utf-8");

浏览器将显示出正确的结果,我们在IE中右键–编码(如果没有IE8,可以下载360急速浏览器,然后右键–切换到IE8模式),我们会发现浏览器自动将该网页的编码设置为utf-8,这个时候我们将编码设置为ISO,网页出现乱码,再次刷新网页发现显示正常,查看编码我们会发现,IE又把编码从ISO自动设置为utf-8。这说明什么?说明浏览器会根据Content-Type中的字符集来自动改变网页的编码。

将代码改为:

response.setContentType( "text/html;charset=gbk");

浏览器将显示出正确的结果,在IE中右键–编码,我们会发现浏览器自动将该网页的编码设置为gb2312,那么问题来了,为什么浏览器没有将编码自动设置为gbk?我们在网页上右键–编码–更多,会发现在更多列表里面没有gbk这个编码,也就是说IE不支持gbk编码,这个时候IE会选择默认的编码来处理,也就是gb2312,而gb2312和gbk是兼容的,所以也能显示出正确的结果。对于浏览器默认的字符集编码,我们是可以自己设定的,但是在中文操作系统下,浏览器的默认设置是gb2312

通过上面的实验内容,我们知道setContentType这个方法,如果不设置字符集编码,tomcat会采用自身默认的编码,往往是不支持中文的。如果设置了字符集编码,且浏览器支持该编码,那么浏览器就会自动根据该值设置网页编码,如果浏览器不支持的话,那么就会选择浏览器默认编码。

为了支持中文,我们的最佳实践是将字符集编码设置为gb2312 gbk或者utf-8,这三个都支持中文,浏览器也都支持,当然个人推荐utf-8好一点。

最后一点,该方法要在response.getWriter()之前调用,这样对输出才有效。

总结:setContentType设置响应信息的MIME类型和字符集编码,该值能够控制浏览器的行为。

3.setCharacterEncoding(String charset)
很多人问这个和setContentType有啥区别,其实API已经说得非常明白了:

Sets the character encoding (MIME charset) of the response being sent to the client, for example, to UTF-8. If the character encoding has already been set by setContentType(java.lang.String) or setLocale(java.util.Locale), this method overrides it. CallingsetContentType(java.lang.String) with the String of text/html and calling this method with the String of UTF-8 is equivalent with calling setContentType with the String of text/html; charset=UTF-8.This method can be called repeatedly to change the character encoding. This method has no effect if it is called after getWriterhas been called or after the response has been committed.
Containers must communicate the character encoding used for the servlet response‘s writer to the client if the protocol provides a way for doing so. In the case of HTTP, the character encoding is communicated as part of the Content-Type header for text media types. Note that the character encoding cannot be communicated via HTTP headers if the servlet does not specify a content type; however, it is still used to encode text written via the servlet response‘s writer.

其实这个和setContentType()中的charset的设置作用是一模一样的,不同的是优先级问题。
(1)覆盖问题:我们可以看API的说明,如果已经在setContentType和setLocale中设置了charset,那么setCharacterEncoding会覆盖里面的charset设置。setContentType在前 setCharacterEncoding在后 ,那么后面的会覆盖前面的,反之则不会覆盖。
第一种:setContentType在前 setCharacterEncoding在后
servlet代码:

protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException{
    response.setContentType( "text/html;charset=gb2312");
    response.setCharacterEncoding( "utf-8");
    PrintWriter out = response.getWriter();
    out.println( "<a href=‘www.baidu.com‘>百度</a>" );
}

响应:
技术分享
说明setCharacterEncoding覆盖了setContentType中的charset设置

第二种:setCharacterEncoding在前,setContentType在后
servlet代码:

      response.setCharacterEncoding("utf-8");
      response.setContentType( "text/html;charset=gb2312");
      PrintWriter out = response.getWriter();
      out.println( "<a href=‘www.baidu.com‘>百度</a>" );

响应:
技术分享
说明setCharacterEncoding没有覆盖setContentType中charset设置
(2)如果在setContentType中没有设置charset
servlet代码:

     response.setCharacterEncoding("utf-8");
     response.setContentType( "text/html");
     PrintWriter out = response.getWriter();
     out.println( "<a href=‘www.baidu.com‘>百度</a>" );

响应:
技术分享

我们把setCHaracterEncoding和setContentType位置调换,结果还是一样的。
说明

setContentType("text/html;charset=utf-8")=setContentType("text/html")+setCharacterEncoding("utf-8")

(3)如果没有setContentType只有setCharacterEncoding
servlet代码:

      response.setCharacterEncoding( "utf-8");
      PrintWriter out = response.getWriter();
      out.println( "<a href=‘www.baidu.com‘>百度</a>" );

响应:
技术分享
并且网页内容显示错误:
技术分享
说明如果没有setContentType,那么就不会返回Content-Type字段,但是setCharacterEncoding仍然对response,getWriter()有效

至于为什么乱码,我们可以分析一下:我们将writer设置为utf-8格式,但是在响应头中并没有返回Content-Type指定charset,所以浏览器将会使用默认的gb2312导致乱码。如果我们将编码改为gb2312或者gbk,那么就
与浏览器默认编码相同,就不会出现乱码。

(4)setCharacterEncoding和setContentType一样,只有在response.getWriter之前调用,才会对输出起作用。这个就不举例说明了。

以上实验说明,setCharacterEncoding只是对Content-Type中charset进行设置,所以这个方法一般也用不到,用setContentType就已经足够了。

4.setLocal(Local loc):用于设置本地化信息
(1)如果servlet中调用了这个方法,那么将在响应消息中出现Content-Language头字段
(2)可以设置Content-Type中的charset部分,但是如果已经调用了setContentType()和setCharacterEncoding()设置了charset部分,则不会覆盖
(3)如果没有调用setContentType,则响应消息的Http头中不会显示setLocal的charset部分,但是对response.getWriter()的输出结果起作用
(4)在web.xml中配置locale和encoding的映射关系,如果没有配置,则由服务器各个厂商自己决定

首先在web.xml中配置:

<locale-encoding-mapping-list>
       <locale-encoding-mapping >
            <locale >zh_CN </locale >
            <encoding >GB2312 </encoding >
       </locale-encoding-mapping >
</locale-encoding-mapping-list >

该配置指定了zh_CN(中文)的对应的字符集编码为GB2312

实验1:
servlet代码:

     response.setContentType("text/html;charset=utf-8");
     Locale locale = new Locale( "zh", "CN");
     response.setLocale(locale);
     PrintWriter out = response.getWriter();
     out.println( "<a href=‘www.baidu.com‘>百度</a>" );

响应:
技术分享

我们可以看到在响应消息中多了Content-Language头字段,指定了语言为zh_CN,同时Content-Type中的charset=utf-8没有被覆盖

实验2:
servlet代码:

  response.setContentType("text/html");
  Locale locale = new Locale( "zh", "CN");
  response.setLocale(locale);
  PrintWriter out = response.getWriter();
  out.println( "<a href=‘www.baidu.com‘>百度</a>" );

响应:
技术分享
Content-Type中的charset变成了GB2312,这说明如果在setContentType中没有指明charset,那么将会被setLocal中的字符集覆盖

实验3:
servlet代码:

      response.setContentType( "text/html");
      Locale locale = new Locale( "zh", "CN");
      response.setCharacterEncoding( "utf-8");
      response.setLocale(locale);
      PrintWriter out = response.getWriter();
      out.println( "<a href=‘www.baidu.com‘>百度</a>" );

响应:
技术分享
说明如果setCharacterEncoding设置了charset,那么setLocale()中的字符集编码将不能覆盖

以上3个实验说明setLocale中对charset的设置的优先级比setContentType和setCharacterEncoding要低

实验4:
servlet代码:

      Locale locale = new Locale("zh", "CN");
      response.setLocale(locale);
      PrintWriter out = response.getWriter();
      out.println( "<a href=‘www.baidu.com‘>百度</a>" );

响应:
技术分享
我们可以发现,如果没有设置Content-Type,则不会显示setLocale中的charset,但是对response.getWriter中获得的PrintWriter仍然有效。也就是说,PrintWriter仍然将使用GB2312向客户端输出:百度 这段文本

总结:
在HttpServletResponse中:
**(1)setContentType setCharacterEncoding setLocale对Content-Type头字段中的charset设置都有效,优先级为:
setContentType=setCharacterEncoding>setLocale
有的书上说setCharacterEncoding>setContentType,但是经过试验表明这取决于两者的先后顺序,所以我认为他们对设置charset优先级相同
(2)如果没有调用setContentType,那么响应消息中不会出现Content-Type头字段。在这种情况下如果调用了setCharacterEncoding和setLocale指定了charset,那么这个charset对response.getWriter获得的
PrinterWriter仍然有效果。
(3)上面三个都必须在getWriter和response提交之前调用才有效
(4)setLocale除了设置charset之外,还会增加头字段Content-Language,locale映射在web.xml中配置**

若有错误,欢迎批评指正!

response.setContentType response.setCharacterEncoding response.setLocale实验总结

标签:response   charset   contentype   setlocale   charactere   

原文地址:http://blog.csdn.net/fanjiyu1991/article/details/45561853

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!