Response对象
一、 Response设置响应数据
二、Response实现重定向
这会导致浏览器重新发起一次新的请求(第二次请求),所以用户能在地址栏看到跳转后的新地址。
1、语法
response.sendRedirect("目标地址");
这个方法会返回一个状态码
302 Found
,并在响应头中设置Location
。
或者(比较麻烦的写法):
2、例子
示例1:重定向到同一个项目中的页面
response.sendRedirect("/myapp/login.jsp");
注意:这里的路径是以Web应用的根路径为起点,所以建议这样写:
response.sendRedirect(request.getContextPath() + "/login.jsp");
确保无论项目部署在哪,路径都能正确跳转。
示例2:重定向到外部网站
response.sendRedirect("https://www.baidu.com");
3、和请求转发的区别
特性 | 请求转发 forward() | 重定向 sendRedirect() |
---|---|---|
发出请求次数 | 1 次 | 2 次(浏览器又请求一次) |
地址栏是否变化 | ❌ 不变 | ✅ 会变 |
是否共享 request 数据 | ✅ 可以 | ❌ 不可以(因为是两个请求) |
是否只能跳转本项目 | ✅ 是 | ❌ 否,可以跳转外部网址 |
性能 | 较高 | 略低(多一次网络请求) |
是否可以跳转到 WEB-INF | ✅ 可以 | ❌ 不可以(浏览器无法访问 WEB-INF) |
4、重定向过程图解
1. 浏览器请求 A↓
2. Servlet A 执行:response.sendRedirect("/home.jsp")↓
3. 服务器响应状态码 302,响应头 Location: /home.jsp↓
4. 浏览器再次请求 /home.jsp↓
5. 返回最终页面
重定向有两种:
一种是302响应,称为临时重定向;
一种是301响应,称为永久重定向。
两者的区别是,如果服务器发送301永久重定向响应,浏览器会缓存
/hi
到/hello
这个重定向的关联,下次请求/hi
的时候,浏览器就直接发送/hello
请求了。
如果要实现301永久重定向,可以这么写:
resp.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); // 301
resp.setHeader("Location", "/hello");
5、重定向的常见使用场景
场景 | 原因 |
---|---|
登录成功后跳转主页 | 避免表单重复提交 |
未登录用户跳转登录页 | 地址栏要变 |
完成注册后跳到成功页 | 显式通知用户新页面 |
跳转到外部页面 | 只能用重定向 |
请求转发的典型重用场景:
场景 | 原因 / 好处 |
---|---|
表单提交失败回显 | 可保留 request 中错误信息 |
Servlet → JSP 显示 | JSP 放在 WEB-INF 更安全 |
多 Servlet 组合调用 | 数据共享,模块化开发 |
页面控制器统一跳转 | 动态页面跳转 |
错误页面处理 | web.xml 中统一配置 |
登录拦截失败 → 登录页 | 路径私有、数据传递 |
判断标准(记忆口诀):
“数据要共享 → 用转发,地址需变 → 用重定向”
6、注意事项
-
重定向路径是客户端行为,必须是可被访问的 URL(不能是
WEB-INF
下) -
路径写法推荐加上
request.getContextPath()
,避免部署路径问题 -
重定向后不能再向浏览器输出内容(比如
response.getWriter().write(...)
)
7、总结:
response.sendRedirect()
是一种 客户端跳转,浏览器地址栏会改变,适合登录、退出、跳转外部页面等场景,但无法共享请求数据,不能访问WEB-INF
中的资源。
三、路径问题:是否需要加上虚拟目录
四、跨域的问题
1、什么是“跨域”?
跨域是指:浏览器中的 JavaScript 代码,请求了一个“不同源”的资源,就会触发浏览器的同源策略限制,从而引发跨域问题。
2、什么算“不同源”?
浏览器认为“源”由 三部分组成:
协议(scheme) + 域名(host) + 端口(port)
只要这三者有任何一个不相同,就是跨域!
举例说明:
场景 | 是否跨域 | 原因 |
---|---|---|
http://a.com 请求 http://a.com | ❌ 否 | 同源 |
http://a.com 请求 http://a.com:8080 | ✅ 是 | 端口不同 |
http://a.com 请求 https://a.com | ✅ 是 | 协议不同 |
http://a.com 请求 http://b.com | ✅ 是 | 域名不同 |
http://localhost 请求 http://127.0.0.1 | ✅ 是 | 域名不同(即使指向同一台机器) |
3、什么情况下会遇到跨域问题?
1. 浏览器中用 JavaScript 发请求(XHR、fetch、axios)
// 页面在 http://localhost:3000
fetch("http://localhost:8080/api/user"); // 跨域!不同端口
只有浏览器才有“同源策略”,所以你在:
-
Postman
-
curl
-
后端服务器之间互相调用
是不会有跨域限制的!
2. 前端单独部署,后端单独部署
典型的开发结构:
-
前端 Vue/React 项目:
http://localhost:3000
-
后端接口服务:
http://localhost:8080
请求时就会报跨域问题(CORS error)。
常见错误提示:
Access to fetch at 'http://localhost:8080/api/user'
from origin 'http://localhost:3000'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header...
4、跨域如何解决?
方法 | 原理 | 适用场景 |
---|---|---|
✅ 设置响应头 Access-Control-Allow-Origin | 告诉浏览器:我允许你跨域来 | 推荐方式,标准做法 |
反向代理 | 由前端服务器转发请求 | 比如用 Nginx 或 Vite 的 devServer.proxy |
CORS 中间件 | 后端框架(Spring Boot、Express 等)提供的跨域支持 | 推荐 |
5、后端怎么设置 CORS(以 Java 为例)
Spring Boot:
@CrossOrigin(origins = "http://localhost:3000")
@RestController
public class MyController {@GetMapping("/api/user")public User getUser() {return new User("Tom");}
}
或全局配置:
@Configuration
public class CorsConfig {@Beanpublic WebMvcConfigurer config() {return new WebMvcConfigurer() {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOrigins("http://localhost:3000").allowedMethods("*");}};}
}
6、总结:
只要是浏览器中,JS 请求了一个“协议、域名或端口不同”的地址,就会有跨域问题。
解决跨域问题的根本方式是:后端允许这个请求源(设置 CORS 头),或前端使用代理绕过浏览器限制。
五、Response设置响应体
- 响应字符数据:response.getWriter()
- 响应字节数据:response.getOutputStream()
5-1、响应字符数据
1. 设置响应内容类型(MIME)和编码
有时你需要设置额外的响应头,告诉浏览器怎么处理这段响应内容:
response.setContentType("text/html;charset=UTF-8"); // 返回 HTML
// 或者
response.setContentType("application/json;charset=UTF-8"); // 返回 JSON
【注意】:
Servlet 容器(比如 Tomcat)会设置默认的 Content-Type 响应头为
text/html;charset=ISO-8859-1
,而浏览器默认会把响应体当作 HTML 解析。
若是不加Content-type的响应头,HTML标签默认会被解析,但是若是有中文会出现乱码!
2. 获取字符输出流并写出内容
PrintWriter writer = response.getWriter();
writer.write("<h1>Hello, Servlet!</h1>");
// 或写 JSON 字符串
writer.write("{\"status\": \"ok\"}");
writer.close();
示例:
@WebServlet("/responseDemo03")
public class ResponseDemo03 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.setContentType("text/html;charset=UTF-8");// // 必须放在 getWriter() 前面PrintWriter writer = resp.getWriter();// 放前了就会默认使用 ISO-8859-1 编码writer.write("<h1>Hello, Servlet!你好,世界</h1>");writer.write("{\"status\": \"ok\"}");writer.close();}
}
·
5-2、响应字节数据(如图片、文件下载)
1. 设置响应类型(以图片为例)
response.setContentType("image/png");
2. 获取字节输出流,写出二进制数据
ServletOutputStream out = response.getOutputStream();
FileInputStream in = new FileInputStream("d:/image.png");byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) != -1) {out.write(buffer, 0, len);
}in.close();
out.close();
【注意】:
写入完毕后调用
flush()
却是必须的,因为大部分Web服务器都基于HTTP/1.1协议,会复用TCP连接。如果没有调用
flush()
,将导致缓冲区的内容无法及时发送到客户端。此外,写入完毕后千万不要调用
close()
,原因同样是因为会复用TCP连接,如果关闭写入流,将关闭TCP连接,使得Web服务器无法复用此TCP连接。
六、IOUtils工具类
这个工具类在 Java 中做 IO 流操作非常方便和常用,尤其是你处理 Servlet 请求/响应、上传下载文件时,非常好用。
1、什么是 IOUtils?
IOUtils
是 Apache Commons IO 库中的一个工具类:
org.apache.commons.io.IOUtils
它封装了大量操作 InputStream、OutputStream、Reader、Writer 的静态方法,大大简化了 Java 原本冗长的 IO 操作。
2、常用功能(核心方法)
方法名 | 作用 |
---|---|
copy(InputStream in, OutputStream out) | 复制数据流 |
toString(InputStream in, Charset encoding) | 把流转为字符串 |
toByteArray(InputStream in) | 把流转为 byte[] |
closeQuietly(...) | 安全关闭流,不抛异常 |
write(String str, OutputStream out, Charset encoding) | 写字符串到字节输出流 |
readLines(InputStream in, Charset encoding) | 一行一行读取流 |
contentEquals(InputStream a, InputStream b) | 比较两个流的内容是否一样 |
3、使用场景举例
1. Servlet 中读取请求体字符串
String jsonBody = IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8);
2. 下载文件(把文件流写到响应里)
InputStream in = new FileInputStream("d:/logo.png");
ServletOutputStream out = response.getOutputStream();
IOUtils.copy(in, out);
in.close();
out.close();
3. 上传文件:保存上传的 InputStream 到硬盘
InputStream fileStream = uploadedPart.getInputStream();
FileOutputStream out = new FileOutputStream("upload/xxx.jpg");
IOUtils.copy(fileStream, out);
4. 安全关闭流(避免 try-catch-finally)
IOUtils.closeQuietly(inputStream); // 不会抛出 IOException
4、引入方式(依赖)
它属于 Apache 的 commons-io
工具包:
<!-- Maven 依赖 -->
<dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.11.0</version> <!-- 或最新版 -->
</dependency>