Response对象

一、 Response设置响应数据

二、Response实现重定向

这会导致浏览器重新发起一次新的请求(第二次请求),所以用户能在地址栏看到跳转后的新地址。


1、语法

java 复制代码
response.sendRedirect("目标地址");

这个方法会返回一个状态码 302 Found,并在响应头中设置 Location

或者(比较麻烦的写法):


2、例子

示例1:重定向到同一个项目中的页面

java 复制代码
response.sendRedirect("/myapp/login.jsp");

注意:这里的路径是以Web应用的根路径为起点,所以建议这样写:

java 复制代码
response.sendRedirect(request.getContextPath() + "/login.jsp");

确保无论项目部署在哪,路径都能正确跳转。


示例2:重定向到外部网站

java 复制代码
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永久重定向,可以这么写:

java 复制代码
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)

javascript 复制代码
// 页面在 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:

java 复制代码
@CrossOrigin(origins = "http://localhost:3000")
@RestController
public class MyController {
    @GetMapping("/api/user")
    public User getUser() {
        return new User("Tom");
    }
}

或全局配置:

java 复制代码
@Configuration
public class CorsConfig {
    @Bean
    public WebMvcConfigurer config() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedOrigins("http://localhost:3000")
                        .allowedMethods("*");
            }
        };
    }
}

6、总结:

只要是浏览器中,JS 请求了一个"协议、域名或端口不同"的地址,就会有跨域问题。

解决跨域问题的根本方式是:后端允许这个请求源(设置 CORS 头),或前端使用代理绕过浏览器限制。

五、Response设置响应体

  • 响应字符数据:response.getWriter()
  • 响应字节数据:response.getOutputStream()

5-1、响应字符数据

  1. 设置响应内容类型(MIME)和编码

有时你需要设置额外的响应头,告诉浏览器怎么处理这段响应内容:

java 复制代码
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标签默认会被解析,但是若是有中文会出现乱码!

  1. 获取字符输出流并写出内容
java 复制代码
PrintWriter writer = response.getWriter();
writer.write("<h1>Hello, Servlet!</h1>");
// 或写 JSON 字符串
writer.write("{\"status\": \"ok\"}");
writer.close();

示例:

java 复制代码
@WebServlet("/responseDemo03")
public class ResponseDemo03 extends HttpServlet {

    @Override
    protected 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. 设置响应类型(以图片为例)
java 复制代码
response.setContentType("image/png");
  1. 获取字节输出流,写出二进制数据
java 复制代码
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 中读取请求体字符串

java 复制代码
String jsonBody = IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8);

2. 下载文件(把文件流写到响应里)

java 复制代码
InputStream in = new FileInputStream("d:/logo.png");
ServletOutputStream out = response.getOutputStream();
IOUtils.copy(in, out);
in.close();
out.close();

3. 上传文件:保存上传的 InputStream 到硬盘

java 复制代码
InputStream fileStream = uploadedPart.getInputStream();
FileOutputStream out = new FileOutputStream("upload/xxx.jpg");
IOUtils.copy(fileStream, out);

4. 安全关闭流(避免 try-catch-finally)

java 复制代码
IOUtils.closeQuietly(inputStream);  // 不会抛出 IOException

4、引入方式(依赖)

它属于 Apache 的 commons-io 工具包:

XML 复制代码
<!-- Maven 依赖 -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.11.0</version> <!-- 或最新版 -->
</dependency>
相关推荐
Zz_waiting.3 天前
Javaweb - 10.1 Servlet
servlet·tomcat·javaweb
Maỿbe18 天前
实现回显服务器(基于UDP)
java·javaweb·echo·回显服务器
Java永无止境21 天前
Web后端基础:数据库
java·数据库·javaweb·web
Java永无止境1 个月前
Web前端基础:HTML-CSS
java·前端·css·html·javaweb
fanTuanye1 个月前
JavaWeb是什么?总结一下JavaWeb的体系
java·大数据·javaweb·基础·体系
hello1114-2 个月前
Redis学习打卡-Day2-缓存更新策略、主动更新策略、缓存穿透、缓存雪崩、缓存击穿
java·redis·学习·缓存·javaweb
白白糖2 个月前
一、Javaweb是什么?
javaweb
hello1114-2 个月前
JavaWeb学习打卡-Day6-SpringBean管理、SpringBoot自动装配、Maven高级
spring boot·学习·maven·javaweb
幽络源小助理2 个月前
SpringBoot物资管理系统 | JavaWeb项目设计与实现
java·springboot·javaweb