HttpServletResponse
对象是由 Servlet 容器创建并传递给 Servlet 的 service()
方法(以及间接传递给 doGet()
, doPost()
等方法)的。它的核心作用是让 Servlet 能够向客户端(通常是浏览器)发送 HTTP 响应。
通过 HttpServletResponse
对象,我们可以:
- 设置响应状态码 (Status Code)
- 设置响应头 (Headers)
- 设置 Cookie
- 写入响应体 (Response Body),即发送内容回浏览器
下面我们详细看看如何进行这些操作:
1. 设置响应状态码 (Status Code)
状态码告诉浏览器请求的处理结果(例如,成功、未找到、服务器错误等)。
方法:
response.setStatus(int sc)
: 设置指定的 HTTP 状态码。response.sendError(int sc)
: 发送一个指定的状态码给客户端(通常会附带一个简单的错误页面)。response.sendError(int sc, String msg)
: 发送一个指定的状态码和一条错误消息给客户端。response.sendRedirect(String location)
: 发送一个重定向响应 (状态码 302) 到指定的 URL。
常量:
javax.servlet.http.HttpServletResponse
接口定义了很多常用的状态码常量,例如:HttpServletResponse.SC_OK
(200)HttpServletResponse.SC_CREATED
(201)HttpServletResponse.SC_NO_CONTENT
(204)HttpServletResponse.SC_MOVED_PERMANENTLY
(301)HttpServletResponse.SC_FOUND
(302) -sendRedirect
默认使用这个HttpServletResponse.SC_BAD_REQUEST
(400)HttpServletResponse.SC_UNAUTHORIZED
(401)HttpServletResponse.SC_FORBIDDEN
(403)HttpServletResponse.SC_NOT_FOUND
(404)HttpServletResponse.SC_INTERNAL_SERVER_ERROR
(500)
示例:
// 设置成功状态码 response.setStatus(HttpServletResponse.SC_OK); // 如果资源未找到 // response.sendError(HttpServletResponse.SC_NOT_FOUND, "The requested resource was not found."); // 重定向到另一个页面 // response.sendRedirect("http://www.example.com/newPage");
注意: 设置状态码或调用
sendError
/sendRedirect
应该在向响应体写入任何内容 之前 进行。
2. 设置响应头 (Headers)
响应头包含关于响应的元数据,例如内容类型、缓存控制、自定义信息等。
方法:
response.setHeader(String name, String value)
: 设置一个具有给定名称和值的头。如果该头已存在,则新值将覆盖旧值。response.addHeader(String name, String value)
: 添加一个具有给定名称和值的头。允许同一个头名称有多个值。response.setContentType(String type)
: 设置响应内容的 MIME 类型(例如 “text/html”, “application/json”, “image/jpeg”)。这实际上是设置Content-Type
头的一个便捷方法。response.setCharacterEncoding(String charset)
: 设置发送到客户端的响应的字符编码(例如 “UTF-8”)。通常与setContentType
一起使用,或者直接在setContentType
中指定,如response.setContentType("text/html; charset=UTF-8");
。response.setContentLength(int len)
/response.setContentLengthLong(long len)
: 设置响应体的长度(以字节为单位)。
示例:
// 设置内容类型为 HTML,并使用 UTF-8 编码 response.setContentType("text/html; charset=UTF-8"); // 或者分两步: // response.setContentType("text/html"); // response.setCharacterEncoding("UTF-8"); // 设置自定义头 response.setHeader("X-Custom-Info", "This is my custom header value"); // 设置缓存控制,禁止缓存 response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1 response.setHeader("Pragma", "no-cache"); // HTTP 1.0 response.setDateHeader("Expires", 0); // Proxies // 如果你知道响应体的确切字节数 // byte[] responseBodyBytes = ...; // response.setContentLength(responseBodyBytes.length);
注意: 设置响应头也应该在向响应体写入任何内容 之前 进行。
3. 设置 Cookie
Cookie 是服务器发送到用户浏览器并保存在本地的一小块数据,它们会在浏览器下次向同一服务器发起请求时被携带并发送到服务器上。
步骤:
- 创建一个
javax.servlet.http.Cookie
对象。 - 可选地,设置 Cookie 的属性 (如过期时间
setMaxAge()
, 路径setPath()
, 域setDomain()
, 安全性setSecure()
,setHttpOnly()
,setSameSite()
)。 - 使用
response.addCookie(Cookie cookie)
将 Cookie 添加到响应中。这会生成一个Set-Cookie
响应头。
- 创建一个
示例:
// 创建一个新的 Cookie Cookie userCookie = new Cookie("username", "john_doe"); // 设置 Cookie 的有效期为 1 小时 (3600 秒) userCookie.setMaxAge(3600); // 设置 Cookie 的路径,使其对整个应用可见 userCookie.setPath(request.getContextPath() + "/"); // 或者简单地 "/" // (可选) 设置为 HttpOnly,防止 JavaScript 访问,增强安全性 userCookie.setHttpOnly(true); // (可选) 设置为 Secure,仅通过 HTTPS 传输 // userCookie.setSecure(true); // (可选,现代浏览器推荐) 设置 SameSite 属性 // userCookie.setSameSite("Lax"); // 或 "Strict" 或 "None" (None 需要 Secure=true) // 将 Cookie 添加到响应中 response.addCookie(userCookie); // 删除一个 Cookie (通过设置 maxAge 为 0) // Cookie deleteCookie = new Cookie("old_cookie_name", ""); // deleteCookie.setMaxAge(0); // deleteCookie.setPath("/"); // response.addCookie(deleteCookie);
注意: 添加 Cookie 也是通过设置响应头 (
Set-Cookie
) 实现的,所以也应该在向响应体写入任何内容 之前 进行。
4. 将内容发送回浏览器 (写入响应体)
一旦状态码和头信息设置完毕,你就可以开始向响应体写入实际内容了。你有两种方式获取输出流:
response.getWriter()
: 返回一个java.io.PrintWriter
对象,用于发送字符文本数据 (如 HTML, XML, JSON, plain text)。- 在使用
getWriter()
之前,应该先通过response.setContentType()
和/或response.setCharacterEncoding()
设置正确的字符编码。
- 在使用
response.getOutputStream()
: 返回一个javax.servlet.ServletOutputStream
对象,用于发送二进制数据 (如图片, PDF, ZIP 文件)。
重要: 你在一个响应中只能调用 getWriter()
或 getOutputStream()
一次。调用其中一个后,就不能再调用另一个了,否则会抛出 IllegalStateException
。
示例 (使用
PrintWriter
发送 HTML):response.setContentType("text/html; charset=UTF-8"); // response.setStatus(HttpServletResponse.SC_OK); // 默认是 200 OK,可以不显式设置 PrintWriter out = response.getWriter(); out.println("<!DOCTYPE html>"); out.println("<html>"); out.println("<head>"); out.println("<meta charset=\"UTF-8\">"); out.println("<title>My Servlet Response</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>Hello from Servlet!</h1>"); out.println("<p>This is a dynamic response.</p>"); out.println("</body>"); out.println("</html>"); // out.flush(); // 可选,容器通常会自动 flush // out.close(); // 可选,容器通常会自动关闭
示例 (使用
ServletOutputStream
发送图片 - 假设imageData
是一个byte[]
):// byte[] imageData = ... ; // 从文件或数据库加载图片数据 // response.setContentType("image/jpeg"); // response.setContentLength(imageData.length); // // response.setStatus(HttpServletResponse.SC_OK); // ServletOutputStream sos = response.getOutputStream(); // sos.write(imageData); // sos.flush(); // sos.close();
完整示例 (一个简单的 Servlet):
package com.example;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1. 设置状态码 (默认是 200 OK,如果一切正常,可以不显式设置)
response.setStatus(HttpServletResponse.SC_OK);
// 2. 设置响应头
response.setContentType("text/html; charset=UTF-8");
response.setHeader("X-Server-Time", new Date().toString());
// 3. 设置 Cookie
Cookie visitCookie = new Cookie("lastVisit", String.valueOf(System.currentTimeMillis()));
visitCookie.setMaxAge(60 * 60 * 24 * 7); // 7 days
visitCookie.setPath(request.getContextPath() + "/");
visitCookie.setHttpOnly(true);
response.addCookie(visitCookie);
// 4. 获取 PrintWriter 并写入响应体
// (注意:一旦调用 getWriter() 或 getOutputStream(),响应头就被认为是“已提交”,不能再修改状态码或头信息)
PrintWriter out = response.getWriter();
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<meta charset=\"UTF-8\">");
out.println("<title>Servlet Response</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Hello, World from Servlet!</h1>");
out.println("<p>Welcome! Your request was processed successfully.</p>");
out.println("<p>Check your browser's developer tools for the 'X-Server-Time' header and the 'lastVisit' cookie.</p>");
out.println("</body>");
out.println("</html>");
// 通常不需要显式调用 out.close(),因为 Servlet 容器会在请求处理完成后自动关闭它。
// 但如果是在 Filter 中或有特殊资源管理需求,可能需要。
}
}
关键点总结:
- 顺序很重要: 设置状态码、响应头和 Cookie 必须在第一次调用
response.getWriter()
或response.getOutputStream()
之前完成,或者在响应被提交(flushed)之前完成。一旦响应体开始写入,头信息就不能再更改了。 getWriter()
vsgetOutputStream()
: 只能选择一个,不能同时使用。- 字符编码: 对于文本内容,务必设置正确的字符编码(通常是 UTF-8)以避免乱码问题。
- 容器管理: Servlet 容器负责在请求处理结束后刷新和关闭输出流。
通过这些方法,HttpServletResponse
提供了全面的控制,使 Servlet 能够构建并发送各种类型的 HTTP 响应给客户端。