起源之路——Servlet(四)

响应

什么是响应

响应对象是请求到达服务器后,服务器处理的结果返回到客户端的所有信息。在HTTP协议中,这些信息是包含在从服务器传输到客户端的HTTP头信息或响应的消息体中。

缓冲

servlet容器允许(但不要求)缓存输出到客户端的内容,通常服务器默认执行缓存,但也允许servlet来指定缓存的参数。

  • getBufferSize
    该方法返回底层缓冲区的大小,如果没有使用,则必须返回0。

  • setBufferSize
    该方法提供给servlet设置一个最佳缓冲大小的值。不一定要分配servlet请求大小的缓冲区,但至少和请求的大小相同,同时允许容器重用一组固定大小的缓冲区,如果合适,可以提供一个比请求更大的缓冲区。该方法必须在ServletOutputStream或Writer写任何内容前调用,如果已经写了内容或响应对象已经提交,则必然抛出IllegalStateException。

  • isCommitted
    该方法返回一个表示是否有任何响应字节已经返回到客户端的Boolean值。

  • reset
    当响应没有提交时,该方法清空缓冲区的数据。头信息、状态码和在调用reset之前servlet电泳getWriter或getOutputStream设置的状态也必须被清空。

  • resetBuffer
    当响应没有被提交,该方法清空缓冲区中的内容,但不清空请求头和状态码。

  • flushBuffer
    该方法强制刷出缓冲区的内容到客户端。

如果响应已经提交并且reset或resetBufffer方法已被调用,则必须抛出IllegalStateException,响应及它关联的缓冲区将保持不变。

当使用缓冲区时,容器必须立即刷出填满的缓冲区内容客户端。如果这是最早发送客户端的数据,且认为响应被提交了。

servlet通过setHeader方法来设置HTTP响应头,HTTP头通常采用键值对的方式存储,因此在调用setHeader方法时,前面的头会被后面同名的头覆盖。

addHeader方法向头信息集合中添加一个头值,addHeader方法提供一个不覆盖之前同名头信息的方式,该方法总是向头信息中添加一个新的首部。

头可能包含表示int或Date对象的数据,因此HTTPServletResponse接口提供了一些方法允许servlet对适当数据类型用正确的格式设置一个头,例如:setIntHeader等等。

头必须在响应提交前设置,响应提交后的头设置将被servlet容器忽略。

servlet程序员负责保证为servlet生成的内容设置何时的响应对象的Content-Type头。HTTP1.1规范中没有要求在HTTP响应中设置此头,当没有设置该类型是,servlet容器也不能设置默认类型。

非阻塞IO

非阻塞IO仅对在Servlet和Filter中的异步请求处理和升级处理有效。否则,应调用ServletInputStream.setReadListener或ServletOutputStream.setWriterListener方法时将会抛出IllegalStateException。

WriteListener提供了如下适用于容器调用的回调方法。

  • WriteListener

    • void onWritePossible() :当一个WriteListener注册到ServletOutputStream时,当可以写数据时该方法将被容器首次调用。仅当ServletOutputStream的isReady方法返回false,容器随后调用该方法。
    • onError(Throwable t) :当处理响应过程中出现错误时回调。
  • ServletOutputStream

  • boolean isReady() :如果往ServerletOutputStream写会成功,则该方法返回true,其他情况返回false。如果该方法返回true,则可以在servletOutputStream上执行写操作,如果没有后续的数据能写到输出流中,那么直到底层数据被刷出之前,该方法将一直返回false。并且在此时容器将调用WriteListener的onWritePossible方法。随后调用该方法将返回true。
  • void setWritelistener(Writerlistener listerner) :关联WriteListener和当前的ServletOutputStream,当ServletOutputStream可以写入数据时容器会调用WriteListener的回调方法。注册了WriteListener将开始非阻塞IO。此时再切换到传统IO是非法的。

注意:容器必须线程安全的访问WriteListener中的方法。

简便方法

HTTPServletResponse提供sendRedirect和sendError方法将设置适当的头和内容体将客户端重定向到另一个地址。使用相对URL路径调用该方法是合法的,但底层的容器必须将传回到客户端的相对地址转换为全路径URL。如果给定的URL是不完整的,且不能转换为一个有效的URL,则必然抛出IllegalArgumentException。

sendError方法将设置适当的头和内容体用于返回给客户端返回错误消息。sendError方法提供一个可选的String参数来指定错误的内容体。

如果响应已经提交并终止,这两个方法调用后servlet将不会产生到客户端的后续的输出。这两个方法调用后如果有数据继续写到响应,这些数据被忽略。如果数据已经写到响应的缓冲区,但没有返回到客户端。则响应缓冲区中的数据必须被清空,并被使用这两个方法设置的数据替换。如果响应已提交,则必然抛出IllegalStateException。

国际化

servlet应设置响应的locale和字符集。嗲用ServletResponse.setLocale方法设置locale。该方法可以重复调用;在响应被提交后调用该方法无效。如果在页面被提交之前servlet没有设置locale,则将会使用容器默认的locale来确定响应的locale,但是没有指定与客户端通信的规范,在使用HTTP情况下的Content-Language头,如果该元素不存在或没有提供映射,setLocale使用容器依赖的映射。

setCharacterEncoding,setContentType和setLocale方法可以被重复的调用来改变字符编码,如果在servlet响应的getWriter方法已经嗲用之后或响应被提交之后,调用相关方法无效。只有当给定的上下文类型字符串提供了一个charset属性值,调用setContentTyoe可以设置字符编码。只有在既没有调用setCharacterEncodeing也没有调用setContentType来设置字符编码之前调用setLocale才可以设置字符编码。

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

如果使用的协议提供了一种这样做的方式,容器必须传递servlet响应的writer使用的locale和字符编码到客户端。在使用HTTP的情况下,locale可以使用Content-Language头传递,字符编码可以作为用户指定文本媒体类型的Content-type头的一部分传递。如果没有指定上下文类型,字符编码不能通过HTTP头传递;但是仍是可以使用它来编码通过servlet响应的writer写的文本。

结束响应对象

当响应被关闭时,容器必须立即刷出响应缓冲区中的所有剩余内容到客户端。以下时间表明servlet满足了请求且响应对象即将关闭:

  1. servlet的service方法终止。
  2. 响应的setContentLength或setContentLengthLong方法指定了大于零的内容量,且已经写入到响应。
  3. sendError方法已调用。
  4. sendRedirect方法已调用。
  5. AsyncContext的complate方法已调用。

响应对象的生命周期

每个响应对象只有在servlet的service方法的范围内或filter的doFilter方法范围内有效,除非该组件管理的请求对象开启了异步处理。如果相关请求启动了异步处理,那么知道AsyncContext的complate方法被调用,请求对象一直有效。为了避免响应对象创建的性能开销,容器通常回收响应对象。在相关的请求的startAsync还没有调用时,开发人员必须意识到保持到响应对象引用,超出之上描述的范围可能导致不确定行为。


参考链接: 来自waylau翻译的《Java Servlet 3.1 规范》
自己使用整理收集,如有侵权 请联系删除!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值