Servlet规范之The Response

Posted 顧棟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Servlet规范之The Response相关的知识,希望对你有一定的参考价值。

The Response

文章是对 JSR-000340 JavaTM Servlet 3.1 Final Release的Java™ Servlet规范的翻译,尚未校准

文章目录


响应对象封装了将从服务器返回给客户端的所有信息。在HTTP协议中,这些信息是通过HTTP头或请求的消息体从服务器传送到客户端的。

Buffering

为了提高效率,servlet容器可以,但不是必须,缓冲输出到客户端。一般来说,做缓冲的服务器都是默认的,但允许servlet指定缓冲参数。

ServletResponse接口中的下列方法允许Servlet访问和设置缓冲信息。

  • getBufferSize
  • setBufferSize
  • isCommitted
  • reset
  • resetBuffer
  • flushBuffer

这些方法是在ServletResponse接口上提供的,以便在Servlet使用ServletOutputStreamWriter时都能进行缓冲操作。

getBufferSize方法返回正在使用的基础缓冲区的大小。如果没有使用缓冲区,该方法必须返回0(零)的int值。

servlet可以通过使用setBufferSize方法请求一个首选的缓冲区大小。分配的缓冲区不需要是servlet请求的大小,但必须至少和请求的大小一样大。这允许容器重新使用一组固定大小的缓冲区,如果合适的话,提供一个比请求的更大的缓冲区。该方法必须在使用ServletOutputStreamWriter写入任何内容之前调用。如果任何内容已经被写入或响应对象已经被提交,这个方法必须抛出一个IllegalStateException

isCommitted方法返回一个布尔值,表明是否有任何响应字节被返回给客户端。flushBuffer方法强制将缓冲区的内容写入客户端。

响应未提交时,reset方法清除缓冲区中的数据。头信息、状态码和调用getWritergetOutputStream的状态,由servlet在重置调用之前设置,也必须被清除。如果响应没有被提交,resetBuffer方法会清除缓冲区中的内容,而不会清除头信息和状态码。

如果响应被提交,并且调用了resetresetBuffer方法,必须抛出IllegalStateException。响应和其相关的缓冲区将不会改变。

当使用缓冲区时,容器必须立即将填满的缓冲区的内容刷新到客户端。如果这是发送给客户端的第一个数据,那么该响应被认为是已提交的。

Headers

一个Servlet可以通过HttpServletResponse接口的下列方法来设置HTTP响应的头信息。

  • setHeader
  • addHeader

setHeader方法用给定的名称和值设置一个头。以前的头信息被新的头信息所取代。如果该名称存在一组头的值,这些值将被清除并被新的值所取代。

addHeader方法在给定名称的集合中增加一个头值。如果没有与该名称相关联的标头,就会创建一个新的标头集。

头信息可以包含代表 intDate对象的数据。HttpServletResponse接口的下列方便方法允许servlet使用正确的格式为适当的数据类型设置一个头。

  • setDateHeader
  • setDateHeader
  • addIntHeader
  • addDateHeader

为了成功地传送回客户端,头信息必须在响应提交之前设置。响应提交后设置的头信息将被Servlet容器忽略。

Servlet程序员负责确保在响应对象中为Servlet生成的内容适当地设置Content-Type标头。HTTP 1.1规范并不要求在HTTP响应中设置这个头。当servlet程序员没有设置内容类型时,servlet容器不得设置默认内容类型。

建议容器使用X-Powered-ByHTTP头来发布其实现信息。该字段值应该由一个或多个实现类型组成,如"Servlet/3.1"。可以选择在括号内的实现类型之后添加容器和底层 Java 平台的补充信息。容器应该可以被配置为抑制这个标头。

下面是这个标头的例子。

X-Powered-By: Servlet/3.1
X-Powered-By: Servlet/3.1 JSP/2.3 (GlassFish Server Open Source
Edition 4.0 Java/Oracle Corporation/1.7)

Non Blocking IO

非阻塞IO只适用于Servlet和过滤器中的异步请求处理(如2-10页的2.3.3.3节“Asynchronous processing”所定义),以及升级处理(如2-20页的2.3.3.5节 "Upgrade Processing"所定义)。否则,当调用ServletInputStream.setReadListenerServletOutputStream.setWriteListener时,必须抛出一个IllegalStateException。为了支持Web容器中的非阻塞性写入,除了第3-28页第3.7节 "非阻塞性IO "中描述的对ServletRequest的修改外,还对处理响应相关的类/接口做了以下修改。

WriteListener提供了以下回调方法,容器会适当地调用这些方法。

  • WriteListener
    • void onWritePossible()。当WriteListener被注册到ServletOutputStream时,这个方法将在有可能写入数据时被容器调用。容器随后将调用onWritePossible方法,当且仅当ServletOutputStream上的isReady方法(如下所述)返回false
    • onError(Throwable t). 当处理响应发生错误时调用。

除了WriteListener,以下方法也被添加到 ServletOutputStream类中,以允许开发者与运行时一起检查是否可以写入要发送给客户端的数据。

  • ServletOutputStream的方法
    • boolean isReady()。如果向ServletOutputStream 写操作将成功,该方法返回 “true”,否则将返回 “false”。如果这个方法返回 “true”,可以对ServletOutputStream进行写操作。如果没有进一步的数据可以被写入ServletOutputStream,那么这个方法将返回false,直到底层数据被刷新,此时容器将调用WriteListeneronWritePossible方法。对该方法的后续调用将返回 “true”。
    • void setWriteListener(WriteListener listener). 将WriteListener与这个ServletOutputStream联系起来。当可以写入数据时,容器将调用WriteListener的回调方法。注册一个WriteListener将启动非阻塞的IO。在这一点上切换到传统的阻塞式IO是非法的。

Servlet容器必须以线程安全的方式访问WriteListener中的方法。

Convenience Methods

HttpServletResponse接口中存在以下便利方法。

  • sendRedirect
  • sendError

sendRedirect方法将设置适当的头信息和内容体,将客户端重定向到一个不同的URL。用一个相对的URL路径调用这个方法是合法的,但是底层容器必须把相对路径翻译成一个完全合格的URL,以便传送回给客户端。如果给定了一个部分的URL,并且由于某种原因不能被转换成一个有效的URL,那么这个方法必须抛出一个 “不合法的参数错误”(IllegalArgumentException)。

sendError方法将设置适当的头信息和内容体,以返回给客户端的错误信息。可以为sendError方法提供一个可选的`String’参数,可以用于错误的内容体。

这些方法的副作用是提交响应(如果它还没有被提交),并终止它。在这些方法被调用后,servlet不应进一步向客户端输出。

如果在这些方法被调用后,数据被写到了响应中,那么这些数据将被忽略。如果数据已经写入响应缓冲区,但没有返回给客户端(即响应没有提交),则必须清除响应缓冲区中的数据,并用这些方法设置的数据来替换。如果响应被提交,这些方法必须抛出一个 “非法状态”(IllegalStateException)。

国际化

Servlets应该设置响应的locale和字符编码。使用ServletResponse.setLocale方法来设置locale。该方法可以被反复调用;但在响应提交后的调用没有效果。如果servlet在提交页面之前没有设置locale,容器的默认locale就会被用来确定响应的locale,但在与客户端的通信中没有任何规范,例如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使用一个依赖于容器的映射。setCharacterEncodingsetContentTypesetLocale方法可以被反复调用,以改变字符编码。在调用servlet响应的getWriter方法后或响应提交后进行的调用,对字符编码没有影响。对setContentType的调用只有在给定的内容类型字符串为charset属性提供了一个值时才会设置字符编码。对setLocale的调用只有在setCharacterEncodingsetContentType都没有设置过字符编码的情况下才会设置字符编码。

如果Servlet在调用ServletResponse接口的getWriter方法或提交响应之前没有指定字符编码,则使用默认的ISO-8859-1

如果所使用的协议提供了一种方法,容器必须将servlet响应的写入者所使用的locale和字符编码传达给客户端。在HTTP的情况下,地域是通过 Content-Language头传达的,字符编码是文本媒体类型的 Content-Type头的一部分。请注意,如果servlet没有指定内容类型,就不能通过HTTP头传达字符编码;但是,它仍然被用来对通过servlet响应的写入器写入的文本进行编码。

响应对象的关闭

当一个响应被关闭时,容器必须立即将响应缓冲区中的所有剩余内容冲到客户端。以下事件表明servlet已经满足了请求,响应对象将被关闭。

  • Servlet的service方法的终止。

  • 响应的setContentLengthsetContentLengthLong方法中指定的内容量已经大于零,并且已经写入响应。

  • 调用了sendError方法。

  • 调用了sendRedirect方法。

  • 调用AsyncContext上的complete方法。

响应对象的生命周期

每个响应对象只在servlet的service方法的范围内或过滤器的doFilter方法的范围内有效,除非相关的请求对象为组件启用了异步处理。如果相关请求的异步处理被启动,那么请求对象将保持有效,直到AsyncContext上的complete方法被调用。容器通常会回收响应对象,以避免创建响应对象的性能开销。开发者必须意识到,在上述范围之外,保持对相应请求的startAsync未被调用的响应对象的引用,可能会导致非确定性的行为。

以上是关于Servlet规范之The Response的主要内容,如果未能解决你的问题,请参考以下文章

Servlet之Response对象

Servlet之request和response

servlet之request和response的使用区分

JavaWeb开发之Servlet&Request&Response

servlet_Request_Response

Servlet规范之预览