• 20200311 5. Response


    5. 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 调用 getWritergetOutputStream 设置的状态也必须被清空。如果响应没有被提交, resetBuffer 方法将清空缓冲区中的内容,但不清空请求头和状态码。

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

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

    5.2 头信息

    Servlet 可以使用如下 HttpServletResponse 接口中的方法设置 HTTP 响应头:

    • setHeader
    • addHeader

    setHeader 方法设置一个给定名字和值的 header。之前的 header 将被新的 header 替换。如果已经存在同名的
    header 值的 set, set 中的值会被清空并用新的值替换。

    addHeader 方法使用给定的名字添加一个 header 值到 set。如果没有 header 与给定的名字关联,则创建一个
    新的 set。

    Header 可能包含表示 intDate 对象的数据。以下 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.1"。容器应该可以配置来隐藏该 header。可选的容器补充的信息和底层 Java 平台可以被放在括号
    内并添加到实现类型之后。

    X-Powered-By: Servlet/3.1

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

    5.3 非阻塞 IO

    非阻塞 IO 仅对在 Servlet 和 Filter(2.3.3.3 节定义的, “异步处理”)中的异步请求处理和升级处理
    (2.3.3.5 节定义的,“升级处理”)有效。否则,当调用 ServletInputStream.setReadListener
    ServletOutputStream.setWriteListener 方法时将抛出 IllegalStateException。 为了支持在 Servlet 容器中的非阻塞写,除了在 3-28 页 3.7 节描述的“非阻塞 IO” 对 ServletRequest 做的更改之外,下面做出的更
    改以便于处理响应相关的类/接口。

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

    • void onWritePossible(). 当一个 WriteListener 注册到 ServletOutputStream 时,当可以写数据时该方法将被容器首次调用。当且仅当下边描述的 ServletOutputStreamisReady 方法返回 false,容器随后将调用该方法。

    • onError(Throwable t). 当处理响应过程中出现错误时回调。

    除了 WriteListener 外,还有如下方法被添加到 ServletOutputStream 类并允许开发人员运行时检查是否可以写数据发送到客户端。

    • boolean isReady(). 如果往 ServletOutputStream 写会成功,则该方法返回 true,其他情况会返回 false。如果该方法返回 true,可以在 ServletOutputStream 上执行写操作。如果没有后续的数据能写到
      ServletOutputStream,那么直到底层的数据被刷出之前该方法将一直返回 false。且在此时容器将调用
      WriteListeneronWritePossible 方法。随后调用该方法将返回 true

    • void setWriteListener(WriteListener listener). 关联 WriteListener 和当前的 ServletOutputStream,当 ServletOutputStream 可以写入数据时容器会调用 WriteListener 的回调方法。注册了 WriteListener 将开始非阻塞 IO。此时再切换到传统的阻塞 IO 是非法的。

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

    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
    setContentTypesetLocale 方法可以被重复的调用来改变字符编码。如果在 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 方法终止。
    • 响应的 setContentLengthsetContentLengthLong 方法指定了大于零的内容量,且已经写入到响应。
    • sendError 方法已调用。
    • sendRedirect 方法已调用。
    • AsyncContextcomplete 方法已调用。

    5.7 Response 的生命周期

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

  • 相关阅读:
    APP上线碰到的问题:Non-public API usage
    点语法
    strlen、strcpy、strcat的实现
    2. I/O模型基本说明
    1. 同步、异步、阻塞、非阻塞
    8. 负载均衡请求转发实现
    7.负载均衡算法
    6. Nginx配置示例-高可用集群
    5. Nginx配置示例-动静分离
    4. Nginx配置示例-负载均衡
  • 原文地址:https://www.cnblogs.com/huangwenjie/p/12462511.html
Copyright © 2020-2023  润新知