一、前言
在Servlet中,请求转发 和响应重定向是两种重要的机制,用于控制客户端与服务器之间的交互。本文将探讨Servlet请求转发和响应重定向,更好地理解它们的工作原理和应用场景。
二、内容
2.1 概述
在开发中,我们需要在不同的Servlet(或Servlet)之间进行跳转,以实现功能的模块化,或者说分层设计。
有两种主要的方式可以用于在多个Servlet(JSP)之间进行跳转,即请求转发 和响应重定向。下面我们简单来看一下二者的定义。
(1)请求转发
首先是请求转发。
请求转发是一种将请求从一个Servlet或JSP页面转发到另一个Servlet或JSP页面的方式 。注意,请求转发是服务器跳转,只会产生一次请求(它是服务器内部的操作,客户端对此一无所知。)。
请求转发的代码通常如下所示:
java
request.getRequestDispatcher("/direct/index").forward(request, response);
对于请求转发来说,是在服务器内部完成的,此时浏览器地址栏中的URL并不会发生变化。
注意,在请求转发中,原始请求的信息,包括请求参数和属性,是可以被传递到目标Servlet或JSP页面。
这个在后面示例中会体现。
(2)响应重定向
下面来看一些响应重定向。
响应重定向指的是将请求从一个Servlet或JSP页面重定向到另一个URL的方式 。它会向客户端浏览器发送一个新的URL,然后浏览器会重新发送请求到该URL。注意这里的变化,这就和请求转发不同了。请求转发只会产生一次请求,而响应重定向会产生两次请求。
响应重定向的代码通常如下所示:
java
response.sendRedirect("/MyServlet/direct/index");
注意,在使用响应重定向时,通常需要在目标URL中包含应用程序的上下文路径(context path
)。
上下文路径是Web应用程序在服务器上的根路径,通常是项目名称。
2.2 代码示例
(1)准备工作
下面我们创建一个工程,名称为 MyServlet
。
接着,我们创建两个 Servlet
,分别是 CheckLoginServlet
和 IndexServlet
:
两个 Servlet 的映射地址分别是 /direct/check
和 /direct/index
,初始代码如下:
对于一个简单的用户登录操作来说,首先需要用户信息校验,其次是登录成功后的首页显示。
现在,我们简单来模拟一下用户登录过程,并实现这两个Servlet的跳转。
(2)请求转发的示例
在这里,我们修改 CheckLoginServlet
中的 doGet()
方法:
java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 在控制台输出信息,模拟用户登录成功
System.out.println("用户登录成功...");
// 实现请求转发功能
request.getRequestDispatcher("/direct/index").forward(request, response);
}
这样,就可以在运行时就可以把请求从当前的地址转发给了 IndexServlet
进行处理。
我们来验证一下实现效果。
首先修改配置服务器(Tomcat)上的资源,将我们的工程添加过去:
接着,启动服务器。
在浏览器的地址栏中输入
bash
http://localhost:8080/myServlet/direct/check
回车后效果如下:
从上图中我们可以发现什么?
页面的输出内容是 IndexServlet
的作用效果。同时,地址栏中的URL映射是 direct/check
。没错,这是与CheckLoginServlet
关联的路径,这样的结果表明,请求转发功能设置成功了。
当浏览器请求匹配路径 localhost:8080/myServlet/direct/check
的URL时,CheckLoginServlet
的 doGet
对其打印 "用户登录成功..."
,接着将我们当前的请求给转发到了 IndexServlet
上。从而触发了 IndexServlet
中的 doGet()
方法。
java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 模拟登录成功后的首页展示效果
response.getWriter().println("Index Page!");
}
(3)响应重定向的示例
在之前的例子中,我们使用了请求转发来实现两个 Servlet 的跳转。现在我们换成另一种方式来实现这个效果。
我们修改 CheckLoginServlet
中的 doGet()
方法,如下所示:
java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 在控制台输出信息,模拟用户登录成功
System.out.println("用户登录成功...");
// 实现响应重定向功能
response.sendRedirect("/MyServlet/direct/index");
}
需要注意的是,响应重定向需要增加 contextPath
,即上下文路径(通常是工程名字)。不加这个,访问是有问题的。
我们再来看一下程序的运行效果,当我们再次输入 地址:
bash
http://localhost:8080/myServlet/direct/check
回车后效果如下:
可以看到,我们的结果没有发生变化,但是需要注意到,地址栏中的映射地址发生了变化。从原先的 /direct/check
请求变成了 /direct/index
。
2.3 工作原理对比
我们再来回顾一下。
首先,请求转发是在服务器内部将一个请求发送到另一个资源的处理过程,在整个过程中,客户端(浏览器)并不知道服务器端发生了什么。
大致工作流程如下:
- 客户端发起HTTP请求。
- 第一个
Servlet
处理请求,然后使用RequestDispatcher
将请求传递给第二个Servlet
。 - 第二个
Servlet
处理请求并生成响应。 - 响应返回给客户端。
在这个过程中,客户端只知道自己向第一个Servlet发送了请求,不知道第二个Servlet的存在。
而响应重定向不一样,它指的是客户端(浏览器)重新定向到一个新的URL。在重定向的过程中,服务器会返回一个状态码和一个新的URL给客户端,客户端(浏览器)需要重新发起一个新的请求。
工作流程如下:
- 客户端发起HTTP请求。
- 第一个
Servlet
处理请求,然后通过response.sendRedirect()
将响应中的目标URL发送回客户端。 - 客户端浏览器收到响应后,会发起第二次HTTP请求,前往目标URL。
- 第二个
Servlet
处理第二次请求并生成响应。 - 第二个响应返回给客户端。
如下图所示:
因此,我们可以简单记住,请求转发是服务器跳转,只会产生一次请求。而重定向则是浏览器端跳转,会产生两次请求。
2.4 设置请求自定义属性
我们可以在 Servlet 中创建自定义属性(设置请求属性)和获取请求属性。这些操作允许我们在处理请求期间存储和检索自定义数据。
(1)设置请求属性
使用request.setAttribute(属性名, 属性值)
方法可以设置请求属性。请求属性允许你存储数据,以便在同一请求的不同Servlet
或JSP
页面中共享。
(2)获取请求属性
使用request.getAttribute(属性名)
方法可以获取请求属性的值。
(3)示例
还是之前的例子。
我们在 CheckLoginServlet
中的 doGet()
方法中添加一行代码:
java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 在控制台输出信息,模拟用户登录成功
System.out.println("用户登录成功...");
// 设置请求属性
request.setAttribute("userName", "admin");
// 实现请求转发功能
request.getRequestDispatcher("/direct/index").forward(request, response);
}
这里使用的是请求转发。
当跳转到 IndexServlet
时,我希望输出上面自定义的属性。
简单修改一下代码:
java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String userName = (String)request.getAttribute("userName");
// 模拟登录成功后的首页展示效果
response.getWriter().println("Index Page! Hello, " + userName);
}
启动服务器,访问地址:
bash
http://localhost:8080/myServlet/direct/check
效果如下:
从输出结果也可以看出来,在这个转发过程中,对于 CheckLoginServlet
和 IndexServlet
使用的都是同一个请求对象。
否则,我们在CheckLoginServlet
中设置请求对象的 userName
属性是无法被获取到的。
下面,我们再修改一下程序,将跳转方式改为使用响应重定向:
java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 在控制台输出信息,模拟用户登录成功
System.out.println("用户登录成功...");
// 设置请求属性
request.setAttribute("userName", "admin");
// 实现响应重定向功能
response.sendRedirect("/myServlet/direct/index");
}
重新加载后,页面效果如下:
可以看到,此时输出结果变为了 null
。这是因为 userName
属性在这里是一个空字符串,所以输出 null
。
通过这个例子,也证明了对于重定向来说,实际上浏览器产生了两个请求,在这种情况下,两个 Servlet 是无法共享请求属性的,第一个Servlet设置的请求属性,跳转到第二个Servlet后是无法获取的。
三、总结
本文深入探讨了Servlet请求转发与响应重定向两种机制。
请求转发是一种在服务器内部完成的机制,适用于模块化开发和数据共享,而响应重定向是一种客户端行为,通常用于跳转到不同的URL。了解它们的工作原理和应用场景,可以帮助我们更好地选择合适的机制,以满足不同的需求。