Servlet总结(三)

来源:互联网 发布:全境封锁 知乎 编辑:程序博客网 时间:2024/06/07 05:48

六、ServletResponse

该接口代表的是返回给浏览器的响应,响应包括响应头和响应体。所以这个接口中的方法分为两组:

(一)设置响应头

public void setLocale(Locale loc);public Locale getLocale();public void setContentType(String type);public String getContentType();public void setCharacterEncoding(String charset);public String getCharacterEncoding();public void setContentLength(int len);
字面意义上看,这些方法设置了四个响应的属性:语言,内容类型,字符编码,长度。前三个属性都有对应的get方法,而最后的长度没有。

由于人能看懂的只要字符,而计算机使用的是二进制,所以字符编码永远都是一个重要的问题。ServletResponse接口提供了setCharacterEncoding方法专门来设置字符编码。然而正如在上一篇文章中所提到的,“字符编码”不是一个人在战斗,它似乎总是会和contentType或者Locale联系到一起。实际上,除了setCharacterEncoding,setContentType和setLocale也能设置字符编码。它们的优先级为setLocale < setContentType < setCharacterEncoding,后面的会覆盖前面的设置,反之就不行。

setLocale 在设置语言的同时,也会设置跟这种语言匹配的字符编码,正如在注释所说的那样:

It also sets the response's character encoding appropriately for the locale
setContentType在设置内容类型的同时也会设置该类型指定的字符编码,因为内容类型往往不是单独出现的,后面会指定字符编码,如:text/html;charset=UTF-8。

再看setCharacterEncoding的注释:

* Calling {@link #setContentType} with the <code>String</code>* of <code>text/html</code> and calling* this method with the <code>String</code> of <code>UTF-8</code>* is equivalent with calling* <code>setContentType</code> with the <code>String</code> of* <code>text/html; charset=UTF-8</code>.
意思是说:setCharacterEncoding(“UTF-8”)== setContentType (“text/html;”)== setContentType (“text/html;charset=UTF-8”)

这意味着,UTF-8是默认的字符编码。

另外,也正如跟上一篇文章中分析的相似,这几个方法要在调用getWriter方法之前调用,当然更要在response被提交之前调用。因为getWriter获取的是字符流形式的响应体,而把响应体从二进制转换成字符流就需要字符编码,所以必须在这之前设置好。

其实,我疑惑的是,平时我们需要调用这几个set方法吗?为什么要暴露这几个接口给业务开发人员?这几个不应该是容器来调用的吗?因为浏览器发出请求时,会告诉容器自己能接受的语言、内容类型以及字符编码,容器会根据这些去自动设置;而如果由业务开发人员去设置的话,很容易就会超出范围。

当然也有一种情况,请求不是由浏览器发出的,而是由一种自己可控的程序发出的,这时请求可能不给可接受的字符编码等,然后容器就可能使用默认的,而这不符合要求于是还得调用一下这几个方法。

setContentLength设置响应长度,逻辑上讲,这个方法应该是这响应体写完之后,计算长度之后才去调用的。


(二)设置响应体

public ServletOutputStream getOutputStream() throws IOException;public PrintWriter getWriter() throws IOException;public void setBufferSize(int size);public int getBufferSize();public void flushBuffer() throws IOException;public void resetBuffer();public boolean isCommitted();public void reset();
最基本的就是getOutputStream和getWriter,前者返回字节流,也就是二进制;后者返回字符流。然后我们利用他们返回的结果往其中塞东西。。

二者只能调用其中之一,不能都调用,应该由容器来保证这一点,虽然目前我还不清楚为什么要这样。

getWriter使用的默认字符集是ISO-8859-1。

然后重点是关于buffer的几个方法,为什么要使用buffer呢?这里肯定会涉及到一些很细节很底层的东西,暂时我自己也不是了解的很清楚,但是大概原理还是能猜到的。有时候响应体太大,肯定不会一次性发送给客户端,只能分割成小块一块一块发送。那么这个小块到底是多大,这就是bufferSize去定义了。容器应该会去内存申请一块bufferSize大小的内存,然后把响应体写入到其中,满了之后就发送给浏览器,然后继续存储下面的内容。这就是setBufferSize和

getBufferSize两个方法的任务。

flushBuffer的任务就是立即发送响应,不管buffer有没有满。

resetBuffer清空缓冲区,为重写响应体做准备,但是不会重置响应头。

reset则会清空包括响应头在内的所有数据,这说明在buffer内部,响应头和响应体是分开的。

isCommitted用来查看响应是否已经被提交。


这里留个不成熟的疑惑吧:响应体和响应头是不是分开发送的?不然的话,响应头必然是在第一个buffer中的,当这个buffer被发送之后,以后执行reset时其实不会再清空响应头了。



0 0
原创粉丝点击