Response

来源:互联网 发布:汽车工作知乎 编辑:程序博客网 时间:2024/06/07 22:05

响应封装着从服务器返回到客户端的所有信息。在http中,是服务器传输到客户端的消息通过http头信息或者响应的消息体。

缓存区

servlte容器有一个缓冲的区域,用于临时保存写入的信息(在没有调用flush方法之前),不管是使用ServletOutputStream还是Writer(或者其子类),缓存区的操作都可以通过ServletResponse如下方法来操作缓存区:

getBufferSize:返回使用的底层缓存区域大小。如果没有使用缓冲则为0.

setBufferSize:servlte可以使用setBufferSize方法设置一个缓冲区大小,该方法必须在ServletOutputStream或者Writer使用前调用,否则会抛出异常

isCommitted:返回是否已经有响应字节返回到客户端的Boolean。

flushBuffer:强制刷出缓冲区的内容到客户端。

reset:当响应没有提交,用于清空缓冲区数据。这个方法响应头、状态码等都清空。

resetBuffer:当响应没有提交的时候,清空缓冲区的数据,但是不清空头信息和状态码。

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

头信息

servlte可以使用HttpServletResponse接口中的方法设置http响应头

setHeader 方法设置一个给定名字和值的header。之前的 header 将被新的 header替换。如果已经存在同名的header值的 setset 中的值会被清空并用新的值替换。
addHeader 方法使用给定的名字添加一个header 值到 set。如果没有 header与给定的名字关联,则创建一个新的 set。

响应提交之后,再次设置头信息是无效的。

非阻塞 IO
非阻塞io只对于升级处理或者异步处理有效,否则会报出异常

WriteListener 提供了如下适用于容器调用的回调方法。
WriteListener
■ void onWritePossible(). 当一个 WriteListener 注册到 ServletOutputStream 时,当可以写数据时该方法 将被容器首次调用。当且仅当下边描述的 ServletOutputStream 的 isReady 方法返回 false,容器随后将 调用该方法。
onError(Throwable t).当处理响应过程中出现错误时回调。
除了
WriteListener 外,还有如下方法被添加到ServletOutputStream 类并允许开发人员运行时检查是否可以写数据发送到客户端。
ServletOutputStream
■ boolean isReady().如果往 ServletOutputStream写会成功,则该方法返回 true,其他情况会返回false。如果该方法返回 true,可以在 ServletOutputStream上执行写操作。如果没有后续的数据能写到ServletOutputStream,那么直到底层的数据被刷出之前该方法将一直返回false。且在此时容器将调用WriteListeneronWritePossible方法。随后调用该方法将返回 truevoid setWriteListener(WriteListener listener). 关联 WriteListener 和当且的 ServletOutputStream,当
ServletOutputStream 可以写入数据时容器会调用WriteListener 的回调方法。注册了WriteListener 将开始非阻塞IO。此时再切换到传统的阻塞 IO 是非法的。
容器必须线程安全的访问 WriteListener 中的方法

简便方法

sendRedirect

将设置适当的 header 和内容体将客户端重定向到另一个地址。使用相对 URL 路径调用该 方法是合法的,但是底层的容器必须将传回到客户端的相对地址转换为全路径 URL。无论出于什么原因, 如 果 给 定 的 URL 是 不 完 整 的 , 且 不 能 转 换 为 一 个 有 效 的 URL , 那 么 该 方 法 必 须 抛 出 IllegalArgumentException。

sendError

将设置适当的 header 和内容体用于返回给客户端返回错误消息。可以 sendError 方法提供一 个可选的 String 参数用于指定错误的内容体。 如果响应已经提交并终止,这两个方法将对提交的响应产生负作用。

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

国际化

servlte可以设置response的locale和字符集,ServletResponse.setLocale设置,可以重复调用,但是开始往缓冲区写入数据的之后,设置无效。因为ServletResponse 接口的getWriter 方法被调用或响应被提交之前,如果servlet 没有指定字符编码,默认使用ISO-8859-1。

@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// TODO Auto-generated method stubresp.setLocale(new Locale("zh", "CN"));resp.getWriter().append("asdasdasd").append("加深对看就按是代扣"+resp.getCharacterEncoding()).flush();}

  <locale-encoding-mapping-list>          <locale-encoding-mapping>              <locale>zh_CN</locale>              <encoding>GBK</encoding>          </locale-encoding-mapping>               </locale-encoding-mapping-list> 
这样子就是gbk编码了

setContentType和setCharacterEncoding,如果设置了 setContentType
resp.setHeader("Content-type", "text/html;charset=UTF-8"); 则默认setCharacterEncoding也会跟着被设置

setContentType是告诉浏览器用utf-8字符集来解析,setCharacterEncoding是写入字节流的时候使用什么字符集进行编码。

为什么会乱码呢?

原因在于PrintWriter对象将采用默认的编码的ISO8859-1字符集编码进行Unicode字符串到字节数组的转换,由于IS08859-1字符集中根本没有包括中文字符,Unicode编码的中文字符将被转换成无效的字符编码后输出给客户端。所以必须设置setCharacterEncoding,控制PrintWriter对象中文字符集能正常转成Unicode。这样子浏览器就能先Unicode解码,然后正常解析了。

凡事编码的只要写入数据之前设置都有效,一旦开始写入数据了,那么就是最后那一次有效。

结束响应对象

当响应被关闭时,容器必须立即刷出响应缓冲区中的所有剩余的内容到客户端。
以下事件表明 servlet 满足了请求且响应对象即将关闭:
servlet service 方法终止。
■ 响应的
setContentLength setContentLengthLong 方法指定了大于零的内容量,且已经写入到响应。
sendError 方法已调用。
sendRedirect 方法已调用。
AsyncContext complete 方法已调用。
Response 的生命周期

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