response 对象之重定向
# 50.response 对象之重定向
重定向:和转发一样,也是资源跳转的方式
# 什么是重定向
之前我们已经说过什么是重定向了:
例如我们写了一个 Servlet,路径是/Servlet1;后续我们想要升级 Servlet 的功能,但又不想动老代码,于是新写了一个 Servlet,路径是/Servlet2;此时我们就可以让 Servlet1 返回 302 给浏览器,也就是告诉浏览器,别访问/Servlet1 了,访问/Servlet2 吧,这就是重新定向(从/Servlet1 改为访问 /Servlet2)
# 如何重定向
重定向需要 2 步:
- 告诉浏览器重定向,状态码 302
- 告诉浏览器 B 资源的路径:响应头 location: B 资源的路径
# 代码实现
我们来写个代码实践下。新建一个 Servlet:
package com.peterjxl.response;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 重定向演示
*/
@WebServlet("/responseDemo1")
public class ResponseDemo1 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 访问/responseDemo1,会自动跳转到/responseDemo2资源
System.out.println("/responseDemo1....");
// 1. 设置状态码
resp.setStatus(302);
// 2.设置响应头
resp.setHeader("location", "/hello/responseDemo2");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
其实第一步和第二步中,状态码和 location 是固定的,变化的只有路径,因此有个简便的写法可以一步到位:
response.sendRedirect("/hello/responseDemo2");
当然,这个简便写法的内部还是用的 setStatus
和 setHeader
。
然后新建一个被重定向的 Servlet:
package com.peterjxl.response;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 重定向演示
*/
@WebServlet("/responseDemo2")
public class ResponseDemo2 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("/responseDemo2....");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
重启 Tomcat,访问 http://localhost: 8080/hello/responseDemo1,可以看到 IDEA 控制台输出
/responseDemo1....
/responseDemo2....
2
小结:重定向的步骤如下
//1. 设置状态码为302
response.setStatus(302);
//2.设置响应头location
response.setHeader("location","/hello/responseDemo2");
//简单的重定向方法,完成以上两步的功能
response.sendRedirect("/hello/responseDemo2");
2
3
4
5
6
7
8
# 转发和重定向的区别
forward 转发 和 redirect 重定向的区别:刚好相反,面试常考
forward 转发的特点:
- 转发地址栏路径不变
- 转发只能访问当前服务器下的资源
- 转发是一次请求,可以使用 request 对象来共享数据
redirect 重定向的特点:
地址栏发生变化
重定向可以访问其他站点(服务器)的资源,例如重定向到我的网站
response.sendRedirect("https://www.peterjxl.com/");
1重定向是两次请求(可以通过浏览器控制台验证)。不能使用 request 对象来共享数据(可以通过)
# 关于资源路径
转发的时候没有写虚拟目录,但重定向写了,什么时候加,什么时候不加呢?
首先是路径分类,相对路径和绝对路径。
# 相对路径
相对路径:通过相对路径不可以确定唯一资源,较少使用,因为经常需要确定位置关系
不以/开头,以小数点
.
开头的路径如当前页面下有个 index.html 文件:./index.html
如何使用相对路径:找到当前资源和目标资源之间的相对位置关系
- ./:当前目录
- ../ :后退一级目录
我们新建一个 location.html 文件来演示下,文件内容
<h1>找到当前资源和目标资源之间的相对位置关系</h1>
<P>
当前资源:location.html
http://localhost/day15/location2.html
</P>
<P>
目标资源:
http://localhost/day15/responseDemo2
</P>
<a href="./responseDemo2">
responseDemo2
</a>
2
3
4
5
6
7
8
9
10
11
12
13
14
说明如下:
例如当前资源:http://localhost:8080/hello/location.html
目标资源:http://localhost:8080/hello/responseDemo2
两者所在的是同一个目录下 /hello/
,所以我们可以写成 ./responseDemo2
,由于是同一个目录,./
可以省略
重启 Tomcat,然后访问 http://localhost:8080/hello/location.html
,点击超链接,可以看到能正常跳转
我们可以再写一个不同路径的资源来验证。在 web 目录下新建一个 htmls 文件夹,然后新建一个 location2.html,文件内容如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>演示相对路径</title>
</head>
<body>
<h1>找到当前资源和目标资源之间的相对位置关系</h1>
<p>
当前资源:location2.html
http://localhost:8080/hello/location2.html
</p>
<p>
目标资源:
http://localhost:8080/hello/responseDemo2
</p>
<a href="../responseDemo2">
访问../responseDemo2
</a>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
重启 Tomcat,访问 http://localhost: 8080/hello/htmls/location2.html,点击超链接,查看能否正常跳转
# 绝对路径
绝对路径:通过绝对路径可以确定唯一资源
绝对路径是以/开头的路径,如:http://localhost:8080/hello/responseDemo1
,可以简化为 /hello/responseDemo1
。
至于是否要加上虚拟目录(例如本例中使用 /hello
),是根据请求将来从哪发出的,浏览器还是服务器转发:
- 如果是给客户端浏览器使用:需要加虚拟目录(项目的访问路径)。
<a> , <form>
重定向(因为是从客户端发出的).... 建议动态获取虚拟目录:request.getContextPath()
,避免项目的路径变化导致代码需大量修改 - 如果是给服务器转发使用:不需要加虚拟目录,忘了的同学可以回顾下之前学习 request 转发的代码
RequestDemo7.java
我们修改 location.html,加上一个超链接
<hr>
<h1>绝对路径</h1>
<a href="/hello/responseDemo2">
responseDemo2,不写代表默认
</a>
2
3
4
5
为什么内部转发就不用加虚拟目录,而客户端请求就得加上?举个生活中的例子:在一个学校中,有 1 班和 2 班;两个班级都有个人叫皮特;有一天,一名老师找 1 班的张三,他可以去 1 班门口里喊张三的名字,此时 1 班的张三就知道是找他的;同理,班级内部的人找张三的话,也不用加上班级,因为默认都是找班上的张三(如果要找 2 班的张三,要去 2 班找,而不是在 1 班找)
而如果,老师是在 1 班和 2 班之间的走廊叫张三的话,如果不加上班级,两个张三是无法确定到底叫谁的。
同理,一个服务器上可能部署了多个项目,每个项目的虚拟目录是不同的,如果不加上虚拟目录,服务器是不知道到底访问的哪个目录