Response
响应(response)对象封装了从服务器返回到客户端的所有信息。在HTTP协议中,从服务器传输到客户端的信息通过HTTP头信息或响应的消息体。
5.1 缓冲区
Servlet容器允许但不必为了提高效率而缓冲到客户端的输出。典型的服务器默认都是缓冲的,但允许servlet指定缓冲参数。
ServletResponse接口的如下方法允许servlet访问和设置缓冲信息:
■ getBufferSize
■ setBufferSize
■ isCommitted
■ reset
■ resetBuffer
■ flushBuffer
不管Servlet使用的是一个ServletOutputStream还是一个Writer,ServletResponse接口提供的这些方法允许执行缓冲操作。
getBufferSize方法返回使用的底层缓冲区大小。如果没有使用缓冲,该方法必须返回一个int值0。
Servlet可以请求setBufferSize方法设置一个最佳的缓冲大小。不一定分配servlet请求大小的缓冲区,但至少与请求的大小一样大。这允许容器重用一组固定大小的缓冲区,如果合适,可以提供一个比请求时更大的缓冲区。该方法必须在使用ServletOutputStream 或Writer写任何内容之前调用。如果已经写了内容或响应对象已经提交,则该方法必须抛出IllegalStateException。
isCommitted方法返回一个表示是否有任何响应字节已经返回到客户端的boolean值。flushBuffer方法强制刷出缓冲区的内容到客户端。
当响应没有提交时,reset方法清空缓冲区的数据。头信息,状态码和在调用reset之前servlet调用getWriter或getOutputStream设置的状态也必须被清空。如果响应没有被提交,resetBuffer方法将清空缓冲区中的内容,但不清空请求头和状态码。
如果响应已经提交并且reset或resetBuffer方法已被调用,则必须抛出IllegalStateException,响应及它关联的缓冲区将保持不变。
当使用缓冲区时,容器必须立即刷出填满的缓冲区内容到客户端。如果这是最早发送到客户端的数据,且认为响应被提交了。
5.2 头信息
Servlet可以使用如下HttpServletResponse接口中的方法设置HTTO响应头:
■ setHeader
■ addHeader
setHeader方法设置一个给定名字和值的header。之前的header将被新的header替换。如果已经存在同名的header值的set,set中的值会被清空并用新的值替换。
addHeader方法使用给定的名字添加一个header值到set。如果没有header与给定的名字关联,则创建一个新的set。
Header可能包含表示int或Date对象的数据。以下HttpServletResponse接口提供的便利方法允许Servlet对适当的数据类型用正确的格式设置一个header:
■ setIntHeader
■ setDateHeader
■ addIntHeader
■ addDateHeader
为了成功的传回给客户端,header必须在响应提交前设置。响应提交后的Header设置将被servlet容器忽略。
Servlet程序员负责保证为Servlet生成的内容设置合适的response对象的Content-Type header。HTTP 1.1规范中没有要求在HTTP响应中设置此header。当Servlet程序员没有设置该类型时,Servlet容器也不能设置默认的内容类型。
建议容器使用X-Powered-By HTTP header公布它的实现信息。该字段值应考虑一个或多个实现类型,如"Servlet/3.0"。容器应该可以配置来隐藏该header。可选的容器补充的信息和底层Java平台可以被放在括号内并添加到实现类型之后。
X-Powered-By: Servlet/3.1
X-Powered-By: Servlet/3.1 JSP/2.2 (GlassFish v3 JRE/1.6.0)
5.3 非阻塞IO
为了支持在Servlet容器中的非阻塞写,除了在3-28页3.7节描述的“非阻塞IO” 对ServletRequest做的更改之外,下面做出的更改以便于处理响应相关的类/接口。
WriteListener 提供了如下适用于容器调用的回调方法。
The WriteListener provides the following callback methods which the container invokes appropriately.
■ WriteListener
■ void onWritePossible(). 当一个WriteListener注册到ServletOutputStream时,当且仅当下边描述的ServletOutputStream的canWrite方法被调用并返回false,该容器将回调该方法。
■ onError(Throwable t). 当处理响应过程中出现错误时回调。
除了WriteListener外,还有如下方法被添加到ServletOutputStream类并允许开发人员运行时检查是否可以写数据发送到客户端。
■ ServletOutputStream
■ boolean canWrite(). 如果往ServletOutputStream 写会成功,则该方法返回true,其他情况会返回false。如果该方法返回true,可以在ServletOutputStream 上执行写操作。如果没有后续的数据能写到ServletOutputStream,那么直到底层的数据被刷出之前该方法将一直返回false。且在此时容器将调用WriteListener的onWritePossible方法。随后调用该方法将返回true。
■ void setWriteListener(WriteListener listener). 关联WriteListener和当且的ServletOutputStream,当ServletOutputStream可以写入数据时容器会调用WriteListener的回调方法。注册了WriteListener将开始非阻塞IO。此时再切换到传统的阻塞IO是非法的。
5.4 简便方法
HttpServletResponse提供了如下简便方法:
■ sendRedirect
■ sendError
sendRedirect方法将设置适当的header和内容体将客户端重定向到另一个地址。使用相对URL路径调用该方法是合法的,但是底层的容器必须将传回到客户端的相对地址转换为全路径URL。无论出于什么原因,如果给定的URL是不完整的,且不能转换为一个有效的URL,那么该方法必须抛出IllegalArgumentException。
sendError方法将设置适当的header和内容体用于返回给客户端返回错误消息。可以sendError方法提供一个可选的String参数用于指定错误的内容体。
如果响应已经提交并终止,这两个方法将对提交的响应产生负作用。这两个方法调用后servlet将不会产生到客户端的后续的输出。这两个方法调用后如果有数据继续写到响应,这些数据被忽略。 如果数据已经写到响应的缓冲区,但没有返回到客户端(例如,响应没有提交),则响应缓冲区中的数据必须被清空并使用这两个方法设置的数据替换。如果想要已提交,这两个方法必须抛出IllegalStateException。
5.5 国际化
Servlet应设置response的locale和字符集。使用ServletResponse.setLocale方法设置locale。该方法可以重复的调用;但响应被提交后调用该方法不会产生任何作用。如果在页面被提交之前Servlet没有设置locale,容器的默认locale将用来确定响应的locale,但是没有制定与客户端通信的规范,例如使用HTTP情况下的Content-Language header。
<locale-encoding-mapping-list>
<locale-encoding-mapping>
<locale>ja</locale>
<encoding>Shift_JIS</encoding>
</locale-encoding-mapping>
</locale-encoding-mapping-list>
如果该元素不存在或没有提供mapping,setLocale使用容器依赖的mapping。setCharacterEncoding,setContentType和setLocale方法可以被重复的调用来改变字符编码。如果在servlet 响应的getWriter方法已经调用之后或响应被提交之后,调用相关方法设置字符编码将没有任何作用。只有当给定的content type字符串提供了一个charset属性值,调用setContentType可以设置字符编码。只有当既没有调用setCharacterEncoding也没有调用setContentType去设置字符编码之前调用setLocale可以设置字符编码。
在ServletResponse接口的getWriter方法被调用或响应被提交之前,如果servlet没有指定字符编码,默认使用ISO-8859-1。
如果使用的协议提供了一种这样做的方式,容器必须传递servlet 响应的writer使用的locale和字符编码到客户端。使用HTTP的情况下,locale可以使用Content-Language header传递,字符编码可以作为用于指定文本媒体类型的Content-Type header的一部分传递。注意,如果没有指定content type,字符编码不能通过HTTP header传递;但是仍使用它来编码通过servlet 响应的writer写的文本。
5.6 结束响应对象
当响应被关闭时,容器必须立即刷出响应缓冲区中的所有剩余的内容到客户端。
以下事件表明servlet满足了请求且响应对象即将关闭:
■ servlet的service方法终止。
■ 响应的setContentLength或setContentLengthLong方法指定的内容量大于零并且已经写入到响应。
■ sendError 方法已调用。
■ sendRedirect 方法已调用。
■ AsyncContext 的complete 方法已调用。
5.7 响应对象的生命周期
每个响应对象是只有当在servlet的service方法的范围内或在filter的doFilter方法范围内是有效的,除非该组件关联的请求对象已经开启异步处理。如果相关的请求已经启动异步处理,那么直到AsyncContext的complete方法被调用,请求对象一直有效。为了避免响应对象创建的性能开销,容器通常回收响应对象。在相关的请求的startAsync还没有调用时,开发人员必须意识到保持到响应对象引用,超出之上描述的范围可能导致不确定的行为。
PS:希望大家不吝指正翻译中的错误,希望有兴趣的iteye朋友加入进来一起翻译和学习。
Servlet3.1(JSR340)规范目前处于早期草案阶段,目标是在Java EE 7或更高平台。 Servlet3.0(JSR 315)已经包含在Java EE 6平台。具体请参考本规范网站:http://jcp.org/en/jsr/detail?id=340