0%

响应

Java Web 响应处理:HttpServletResponse 详解

在 Java Web 开发中,服务器对客户端请求的响应由 HttpServletResponse 对象封装。它负责构建 HTTP 响应消息(状态行、响应头、响应正文),并将结果返回给客户端。本文将详细解析 HttpServletResponse 的核心功能,包括状态码设置、响应头管理、响应正文输出及常见应用场景。

HttpServletResponse 概述

HttpServletResponseServletResponse 接口的子接口,专门用于处理 HTTP 协议的响应。它由 Servlet 容器创建,通过 service() 方法传递给 Servlet,开发者通过其提供的方法构建响应内容。

1
2
3
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 通过 resp 构建响应...
}

状态行处理

HTTP 响应状态行由协议版本状态码状态描述组成(如 HTTP/1.1 200 OK)。状态码用于告知客户端请求处理结果,HttpServletResponse 提供以下方法设置状态码:

核心方法

  • setStatus(int sc):设置状态码(如 200 表示成功,404 表示资源不存在)。
  • sendError(int sc):发送错误状态码,并触发容器的错误页面机制(如 404 会显示自定义错误页)。
  • sendError(int sc, String msg):发送错误状态码及自定义描述信息。

常见状态码

状态码 含义 常量(HttpServletResponse) 应用场景
200 请求成功 SC_OK 正常返回响应正文
302 临时重定向 SC_FOUND 页面跳转(如登录后跳首页)
400 客户端请求错误 SC_BAD_REQUEST 参数格式错误
401 未认证 SC_UNAUTHORIZED 未登录访问受保护资源
403 权限不足 SC_FORBIDDEN 登录后无操作权限
404 资源不存在 SC_NOT_FOUND 请求 URL 错误
500 服务器内部错误 SC_INTERNAL_SERVER_ERROR 代码抛出异常

示例

1
2
3
4
5
6
7
8
// 设置成功状态码(默认即为 200,可省略)
resp.setStatus(HttpServletResponse.SC_OK);

// 发送 404 错误
resp.sendError(HttpServletResponse.SC_NOT_FOUND, "页面不存在");

// 临时重定向
resp.sendRedirect("/login"); // 等价于 setStatus(302) + setHeader("Location", "/login")

响应头管理

响应头用于向客户端传递附加信息(如内容类型、缓存策略、重定向地址等)。HttpServletResponse 提供以下方法操作响应头:

核心方法

  • setHeader(String name, String value):设置响应头,若已存在则覆盖原值。
  • addHeader(String name, String value):添加响应头,若已存在则保留多个值。
  • setIntHeader(String name, int value):设置整数类型响应头(如 Content-Length)。
  • setDateHeader(String name, long date):设置日期类型响应头(如 Expires,值为毫秒时间戳)。

常用响应头及应用

响应头 作用描述 示例代码
Content-Type 指定响应正文的 MIME 类型和编码 resp.setHeader("Content-Type", "text/html;charset=UTF-8")
Location 重定向目标 URL(配合 302 状态码) resp.setHeader("Location", "/home")
Cache-Control 控制客户端缓存策略 resp.setHeader("Cache-Control", "no-cache")
Content-Disposition 指示客户端下载文件 resp.setHeader("Content-Disposition", "attachment;filename=file.txt")
Set-Cookie 向客户端设置 Cookie 通常通过 addCookie(Cookie cookie) 间接设置

示例:设置 JSON 响应及编码

1
2
3
4
// 设置响应为 JSON 类型,编码 UTF-8
resp.setContentType("application/json;charset=UTF-8");
// 等价于:
// resp.setHeader("Content-Type", "application/json;charset=UTF-8");

示例:控制页面不缓存

1
2
3
resp.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
resp.setHeader("Pragma", "no-cache"); // 兼容 HTTP 1.0
resp.setDateHeader("Expires", 0); // 过期时间设为 0(立即过期)

响应正文输出

响应正文是服务器返回给客户端的实际内容(如 HTML、JSON、图片等),通过输出流写入。HttpServletResponse 提供两种输出流:

字符输出流(PrintWriter

  • 用于输出字符数据(如 HTML、JSON 文本),需指定字符编码。
  • 方法:getWriter(),默认编码为 ISO-8859-1,需通过 setCharacterEncoding("UTF-8")setContentType(...) 设置编码。

示例:输出 HTML 内容

1
2
3
4
5
6
// 设置编码(需在 getWriter() 前调用)
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
out.println("<h1>Hello, World!</h1>");
out.println("<p>当前时间:" + new Date() + "</p>");
out.flush(); // 手动刷新缓冲区(可选,关闭时自动刷新)

字节输出流(ServletOutputStream

  • 用于输出二进制数据(如图片、文件下载)。
  • 方法:getOutputStream(),直接操作字节,无需编码设置。

示例:输出图片

1
2
3
4
5
// 设置响应类型为 JPEG 图片
resp.setContentType("image/jpeg");
ServletOutputStream os = resp.getOutputStream();
// 读取本地图片并写入输出流
Files.copy(Paths.get("path/to/image.jpg"), os);

注意事项

  • 流的互斥性getWriter()getOutputStream() 不能同时调用,否则会抛出 IllegalStateException
  • 编码设置时机:字符编码需在获取 PrintWriter 前设置,否则无效。
  • 缓冲区刷新:输出流默认带缓冲区,可通过 flush() 手动刷新,或在流关闭时自动刷新。

文件下载实现

利用 HttpServletResponse 可实现文件下载功能,核心步骤为:

  1. 设置 Content-Typeapplication/octet-stream(二进制流);
  2. 设置 Content-Disposition 指示客户端下载并指定文件名;
  3. 通过 ServletOutputStream 写入文件字节。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
// 要下载的文件路径
String filePath = "path/to/file.pdf";
File file = new File(filePath);
String fileName = file.getName();

// 设置响应头
resp.setContentType("application/octet-stream");
// 处理文件名中文乱码(不同浏览器兼容)
String encodedFileName = URLEncoder.encode(fileName, "UTF-8").replace("+", "%20");
resp.setHeader("Content-Disposition", "attachment;filename=\"" + encodedFileName + "\"");
resp.setContentLengthLong(file.length()); // 设置文件大小

// 写入文件字节
try (ServletOutputStream os = resp.getOutputStream();
FileInputStream fis = new FileInputStream(file)) {
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
}
}

重定向与请求转发的区别

特性 重定向(sendRedirect 请求转发(RequestDispatcher.forward
客户端感知 地址栏 URL 会变化(显示重定向目标) 地址栏 URL 不变(显示原请求 URL)
跳转范围 可跨域、跨应用 仅能在当前 Web 应用内
请求对象 新请求(request 对象不同) 同一请求(request 对象可共享)
响应头设置 可设置响应头(如 Location 无法设置响应头(已提交)
适用场景 登录后跳转、跨应用跳转 内部页面跳转(如 MVC 视图渲染)

示例:重定向到登录页

1
resp.sendRedirect("/login?error=1"); // 客户端地址栏变为 /login?error=1

欢迎关注我的其它发布渠道