response对象包含了所有从服务端返回给客户端的信息。在HTTP协议下,这些信息通过HTTP头部或者response的消息体从服务器被传输到客户端。
Buffering
为了提高效率,一个servlet容器可以缓存输出到客户端的内容。典型的缓存服务器会把缓存服务默认打开,但是允许servlet指定缓存参数。
ServletResponse接口里的下列方法允许一个servlet访问和设置缓存参数:
- getBufferSize
- setBufferSize
- isCommitted
- reset
- resetBuffer
- flushBufer
无论servlet是否正在使用ServletOutPutStream或者Write,上述在ServletResponse接口之上提供的方法让缓存操作都能被执行。
方法getBufferSize返回正在使用的Buffer的大小。如果没有缓存被使用,这个方法返回int类型的0。
servlet能够请求通过setBufferSize方法设置的指定大小的buffer。分配的buffer大小不必与servlet请求的大小一样,但是必须不能小于请求的大小。这允许容器重用固定大小的buffer集合,在合适的时机可以提供一个比请求更大的buffer。在用ServletOutputStream 写回任何内容之前,方法setBufferSize必须被调用。如果任何内容被写回,或者response对象被提交,方法setBufferSize抛出IllegalStateException。
方法IsCommitted 返回一个boolean值来标识是否有任何response字节被返回到客户端。方法flushBuffer 强制buffer中的内容被写回到客户端。
方法reset 在response对象没有被提交之前,清除缓存中的数据。Servlet在reset调用之前设置的header和状态码也必须被清除。如果response没有被提交,而且没有清除headers和状态码,resetBuffer 方法可以清除buffer中的内容。
如果response被提交,并且reset或resetBuffer方法被调用,一个IllegalStateException必须被抛出。response及其相关的buffer将不会被改变。
当使用一个buffer,容器必须立即把已满buffer的内容刷新到客户端。如果这是发送给客户端的第一份数据,那么response就被认为被提交了。
Headers
一个servlet能通过HttpServletResponse 接口的下列方法设置HTTP response的headers:
- setHeader
- addHeader
方法setHeader 用指定的名字和值来设置一个header。之前的header会被新的header替代。如果一个名字对应一个头部值的集合,它的值会被清除并且被新值替代。
方法addHeader 添加一个header值到指定名字的集合中。如果没有关联此名字的header存在,新的将会被创建。
Headers可以包含表示一个int或者Date对象数据。下列HttpServletResponse接口的便捷方法允许一个servlet使用正确的格式化类型来设置一个header。
- setIntHeader
- setDateHeader
- addIntHeader
- addDateHeader
为了成功地传输回客户端,headers必须在response被提交之前设置好。在response被提交后设置的header将会被servlet容器忽略。
Servlet程序员负责在response对象中,为servlet生成的内容设置合适的Content-Type头部。HTTP1.1规范不要求在一个HTTP response中设置这个header。当servlet程序员没有设置Content-Type,servlet容器一定不能设置默认的content类型。
推荐容器使用X-Powered-By HTTP头部来发布它的实现信息。域值应该由一个或者多个实现类型组成,比如Servlet/3.0。容器的补充以及底层的Java平台信息可以被添加到括号里实现类型的后面。容器应该是可配置来覆盖这个header。
这是X-Powered-By头部的例子。
- X-Powered-By: Servlet/3.0
- X-Powered-By: Servlet/3.0 JSP/2.2 (GlassFish v3 JRE/1.6.0)
便捷方法
下列便捷方法存在于HttpServletResponse 接口中:
- sendRedirect
- sendError
sendRedirect 方法将设置合适的headers和消息体来把客户端重定向到不同的URL。用一个相对URL路径调用这个方法是合法的,但是当前容器必须把相对路径转换成具体的URL传回客户端。如果一个不完整的URI因为任何一个原因不能被转换为一个合法URL,那么这个方法必须抛出IllegalArgumentException。
sendError方法将为返回给客户端的错误消息设置合适的headers和消息体。有一个可选的字符串参数能够传递给这个函数,这个参数能够被应用在消息体中。
如果response还没有被提交,或者结束,这些方法在提交response时将会有副作用。在这些方法调用之后,不应该再有更多内容输出到客户端了。如果在这些方法调用后,还有数据写到response,这些数据会被忽略。
如果这些数据被写到response buffer,但是没有返回给客户端(i.e response还没有被提交),response buffer中的数据必须被清除并且被通过这些方法设置的数据替代。如果response已经被提交,这些方法必须抛出IllegalStateException。
国际化
Servlets应该设置response的区域和字符编码。区域用ServletResponse.setLocale方法来设置。这个方法能被重复地调用,且在response提交之后调用此方法不会有副作用。如果servlet在页面提交之前没有设置区域,容器会使用默认值来决定response的区域,但是并没为与客户端通信制定规范,比如HTTP中的Content-Language 头部。
<locale-encoding-mapping-list>
<locale-encoding-mapping>
<locale>ja</locale>
<encoding>Shift_JIS</encoding>
</locale-encoding-mapping>
</locale-encoding-mapping-list>
如果这个元素不存在,或者没有提供一个映射,setLocale 使用一个依赖容器的映射。setCharacterEncoding,setContentType和setLocale能重复调用来改变字符编码。在servlet response的getWriter方法已经被调用之后,或者在response提交之后调用此方法对字符编码不会有副作用。
仅当指定的content type字符串为charset 属性提供一个值时,调用setContentType方法来设置字符编码。
仅当setCharacterEncoding和setContentType 之前都没有设置字符编码,调用setLocale方法设置字符编码。
如果在ServletResponse接口的getWriter方法调用或者response被提交之前,servlet没有指定字符编码,会使用默认编码 ISO-8859-1。
如果当前使用的协议提供一种编码方式,容器必须为servlet的writer与客户端交流应用于servlet响应对象的writer的区域和字符编码。使用HTTP时,对于文本媒体类型,字符编码作为Content-Type头部的一部分,那么区域通过Content-Language头部来交流。需要注意的是,如果没有指定content type,servlet字符编码不能通过HTTP头部来交流;然而它仍然用来编码servlet响应对象的writer写回的文本。
Response对象的闭包
当response对象被关闭,容器必须立即把response buffer中所有剩余内容刷新到客户端。下列事件标识servlet已经满足了请求并且response对象将会被关闭:
- servlet的service方法结束了.
- 由response对象中的setContentLength方法指定的内容的长度大于0并且已经被写到response.
- 方法sendError被调用.
- 方法sendRedirect被调用.
- AsyncContext上的complete方法被调用.
Response对象的生命周期
每个response对象仅在一个servlet的service方法范围内,或者在filter的doFilter方法范围内才合法,除非相关的请求对象已经为组件启动了异步处理。如果相关请求上的异步处理开始,请求对象直到complete方法被调用前仍然合法。为了避免创建新response对象的性能消耗,容器通常会重复利用response对象。
开发者必须意识到,维护一个指向response对象的引用,且与此对应的request对象上的startAsync还没有被调用,那么要是这引用指向上述范围之外会导致无法预测的行为。
翻译自 Java Servlet Specification
Version 3.0 Rev a
Author:Rajiv Mordani
Date: December 2010
网友评论