1. 接口的定义

HttpServletResponse 是 ServletResponse 的子接口,所以在学习该接口前,有必要对后者进行一个简单的探索。

依然先看官方文档对 ServletResponse 接口的描述:

Defines an object to assist a servlet in sending a response to the client. The servlet container creates a ServletResponse object and passes it as an argument to the servlet’s service method.

它的作用显而易见,就是一个帮助 servlet 向客户端发送响应的一个对象。servlet 容器会创建一个 ServletResponse 对象并且将该对象作为参数传给 servlet 的 service() 方法。

那么进而联想到 HttpServletResponse 的作用必然就是帮助 HttpServlet 对象向客户端发送响应。在 HttpServlet 类中,重载了 Servlet 类的 service 方法,该方法主要就是用来处理请求业务逻辑的,该方法的定义是这样的: public void service(ServletRequest req, ServletResponse resp),可能学到这里会有疑问,为什么参数的类型不是 HttpServletRequset 和 HttpServletResponse 呢,然而看源码就可以发现,在 service 方法的内部,一开始就对 req 和 resp 对象的类型进行了强转,只是在强转前又做了类型的判断,源码如下:

  1. public void service(ServletRequest req, ServletResponse res)
  2. throws ServletException, IOException
  3. {
  4. HttpServletRequest request;
  5. HttpServletResponse response;
  6. if (!(req instanceof HttpServletRequest &&
  7. res instanceof HttpServletResponse)) {
  8. throw new ServletException("non-HTTP request or response");
  9. }
  10. request = (HttpServletRequest) req;
  11. response = (HttpServletResponse) res;
  12. service(request, response);
  13. }

至此,应该对 HttpServletResponse 有个很清晰的认识了,既然它作为一个“帮手”的角色,那么它的实现类就必须实现该接口定义的方法来帮助 servlet 向客户端发送响应,接下来就看看该接口具体定义了哪些方法。

2. 接口中定义的方法

HttpServletResponse 目前定义了20个方法,此外还定义了一堆代表 HTTP 响应状态码的静态常量。这里只列举部分方法。这些方法见名知意,就不在此多做解释了,具体可见 API 文档。

  • addHeader(String name, String value)
  • sendError(int sc)
  • sendError(int sc, String msg)
  • setHeader(String name, String value)
  • setStatus(int sc)
  • addCookie(Cookie cookie)

不过纵观这个接口中定义的方法,貌似都是在响应行和响应头两部分做工作,那么响应体可能就是由它的父接口 ServletResponse 去处理了。它的父接口也有个实现类 ServletResponseWrapper,那么显然需要 HttpServletResponseWrapper 这个类去继承它。而之前说到的参数 resp 的实际类型就是 HttpServletResponseWrapper 类,所以 resp 可以调用 HttpServletResponse 接口和 ServletResponse 中定义的方法,而后者接口中定义了两个方法用来向浏览器写入数据(响应体),这两个方法分别为 getWriter 和 getOutputStream。

说了一堆很乱,用一张图来总结。
未命名文件 (1).jpg

3. 应用案例 - 请求重定向

所谓重定向就是当客户端 A 请求 B 资源时,B 让 A 去请求 C资源。设置重定向的代码很简单,只有简单的一行,看如下代码:

  1. public class SexgirlServlet extends HttpServlet {
  2. @Override
  3. protected void doGet(HttpServletRequest req, HttpServletResponse resp)
  4. throws ServletException, IOException {
  5. resp.sendRedirect("hello");
  6. }
  7. }

通过调用 resp 的 sendRedirect() 方法即可向客户端发送一个重定向,只有客户端会去请求该方法的参数路径,关于路径的设置参考如下官方描述。

If the location is relative without a leading ‘/‘ the container interprets it as relative to the current request URI. If the location is relative with a leading ‘/‘ the container interprets it as relative to the servlet container root. If the location is relative with two leading ‘/‘ the container interprets it as a network-path reference

当访问 localhost:10086/resp/sexgirl 时,它会将请求重定向为 localhost:10086/resp/hello。