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>
相关推荐
郑洁文3 天前
基于Javaweb的高校网上订餐系统
javaweb·毕设·高校网上订餐系统
初学小白...1 个月前
JavaWeb
javaweb·web
一只大袋鼠1 个月前
SpringMVC 框架中的拦截器
java·springmvc·javaweb·拦截器
一只大袋鼠1 个月前
SpringMVC全局异常处理
java·开发语言·springmvc·javaweb
一只大袋鼠1 个月前
JavaWeb四种文件上传方式(下篇)
java·开发语言·springmvc·javaweb
一只大袋鼠1 个月前
JavaWeb四种文件上传方式(上篇)
java·开发语言·servlet·javaweb
abcnull1 个月前
传统的JavaWeb项目Demo快速学习!
java·servlet·elementui·vue·javaweb
float_com1 个月前
【JavaWeb】----- 登录认证 与 统一拦截架构详解
javaweb
float_com2 个月前
【JavaWeb】----- Linux基础入门
linux·javaweb
夹芯饼干2 个月前
JavaWeb 核心:Request 与 Response 对象全解析与实战
javaweb·重定向·request对象·response对象