会话技术
为什么需要?
- 每个用户在使用浏览器与服务器进行会话的过程中,不可避免各自会产生一些数据,服务器要想办法为每个用户保存这些数据;
- 用户通过浏览器访问 Web 应用时,服务器都需要保存和跟踪用户的状态;由于 HTTP 协议是无协议的,无法保存和跟踪用户状态,因此需要会话技术来解决该问题。
是什么?
- 从打开一个浏览器访问某个站点,到关闭这个浏览器的整个过程,为一次会话。
- 用户开一个浏览器,点击多个超链接,访问服务器多个 web 资源,然后关闭浏览器,整个过程称之为一个会话。
- 会话技术是指在会话中,帮助服务器记录用户状态和数据的技术。
- 会话技术可分为Session(服务端会话技术)和Cookie(客户端服务技术),两者相互关联,可理解为一体的。在Servlet中提供了Cookie对象与HttpSession对象用于维护客户端与服务端的会话状态的维持。
cookie
Cookie(小甜饼)是客户端技术。
- 服务器把每个用户的数据以 cookie 的形式写给并保存在用户各自的浏览器(客户端);服务器端在需要的时候可以从客户端/浏览器读取(基于 HTTP 协议实现),比如登录名,浏览历史等。
- 当用户使用浏览器再去访问服务器中的 web 资源时,就会带着各自的数据去,这样,web 资源处理的就是用户各自的数据。
- Cookie 信息的数据量并不大,安全性相对于Session技术来说比较低,因为客户端可以清除Cookie。
缺点:
- 在 HTTP 请求中,Cookie 是明文传递的,容易泄露用户信息,安全性不高。
- 浏览器可以禁用 Cookie,一旦被禁用,Cookie 将无法正常工作。
- Cookie 对象中只能设置文本(字符串)信息。
- 客户端浏览器保存 Cookie 的数量和长度是有限制的。
工作流程
- 客户端浏览器访问服务器时,服务器通过在 HTTP 响应中增加 Set-Cookie 字段,将数据信息发送给浏览器;
- 浏览器将 Cookie 保存在内存中或硬盘上【调用 setMaxAge(int maxAge) 方法设置最大有效时间实现,单位为秒】;
- 再次请求该服务器时,浏览器通过在 HTTP 请求消息中增加 Cookie 请求头字段,将 Cookie 回传给 Web 服务器服务器根据 Cookie 信息跟踪客户端的状态;
相关API
Cookie 有点象一张表(K-V),分两列,一个是名字,一个是值,数据类型都是 String ;
如何创建一个 Cookie(在服务端创建的)
- Cookie c=new Cookie(String name,String val);
- c.setMaxAge();//保存时间;Cookie 保存到浏览器的内存中,默认浏览器关闭则 Cookie 失效
如何将一个 Cookie 添加到客户端
- response.addCookie(c);
如何读取cookie(在服务器端读取到 cookie 信息)
- request.getCookies();
javax.servlet.http.Cookie 类中提供了一系列获取或者设置 Cookie 的方法,如下表。
返回值类型 | 方法 | 描述 |
---|---|---|
int | getMaxAge() | 用于获取指定 Cookie 的最大有效时间,以秒为单位。 默认情况下取值为 -1,表示该 Cookie 保留到浏览器关闭为止。 |
String | getName() | 用于获取 Cookie 的名称。 |
String | getPath() | 用于获取 Cookie 的有效路径。 |
boolean | getSecure() | 如果浏览器只通过安全协议发送 Cookie,则返回 true;如果浏览器可以使用任何协议发送 Cookie,则返回 false。 |
String | getValue() | 用于获取 Cookie 的值。 |
int | getVersion() | 用于获取 Cookie 遵守的协议版本。 |
void | setMaxAge(int expiry) | 用于设置 Cookie 的最大有效时间,以秒为单位。
|
void | setPath(String uri) | 用于指定 Cookie 的路径。 |
void | setSecure(boolean flag) | 用于设置浏览器是否只能使用安全协议(如 HTTPS 或 SSL)发送 Cookie。 |
void | setValue(String newValue) | 用于设置 Cookie 的值。 |
说明:
【1】setMaxAge(int expiry):
expiry为正数时,浏览器就会把cookie保存到硬盘上,关闭后再次打开浏览器,这些cookie依然有效直到超过设定的过期时间。存储在硬盘上的cookie可以在不同的浏览器进程间共享。
expiry为正0时,表示cookie即不在内存中存活,也不在硬盘上存活;是为了覆盖客户端原来的这个cookie,使其作废。
【2】有效路径Path
Cookie 的 path 属性可以有效的过滤哪些 Cookie 可以发送给服务器、 哪些不发;path属性是通过请求的地址来进行有效的过滤。
规则:cookie1.setPath = /工程路径; cookie2.setPath = /工程路径/aaa;
请求地址: http://ip:端口/工程路径/资源
- cookie1 会发给服务器
- cookie2 不会发给服务器
请求地址: http://ip:端口/工程路径/aaa/资源
- cookie1 会发给服务器
- cookie2 会发给服务器
应用实例
需求:
演示 Cookie 底层实现机制, 创建和读取 Cookie。
流程:
1、创建src\com\edu\cookie\CreateCookie.java ,并在 web.xml 完成配置
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;/*** 演示如何创建cookie,并保存到浏览器*/
public class CreateCookie extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("CreateCookie 被调用...");//1. 创建一个Cookie对象//1) username 该cookie的名字 是唯一, 可以理解成是key//2) lhy : 该cookie的值//3) 可以创建多个cookie,老师就创建了一个//4) 这是cookie在服务器端, 还没有到浏览器
Cookie cookie = new Cookie("key1", "value1");
Cookie cookie2 = new Cookie("key2", "value2");response.setContentType("text/html;charset=utf-8");//2. 将cookie发送给浏览器, 让浏览器将该cookie保存response.addCookie(cookie);response.addCookie(cookie2);PrintWriter writer = response.getWriter();writer.println("<h1>创建cookie成功~</h1>");writer.flush();writer.close();}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}
}
2、访问 CreateCookie.java, 使用浏览器抓包分析 , 创建 Cookie 的底层机制
3、创建src\com\hspedu\cookie\ReadCookie.java
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;/*** 读取从浏览器发送来的cookie信息[底层仍然是http协议]*/public class ReadCookies extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("ReadCookies 被调用..");//1. 通过request对象读取cookie信息Cookie[] cookies = request.getCookies();//2. 遍历cookieif (cookies != null && cookies.length != 0) {for (Cookie cookie : cookies) {System.out.println("cookie name= " + cookie.getName()+ " value= " + cookie.getValue());}}//3. 给浏览器返回信息 response.setContentType("text/html;charset=utf-8");PrintWriter writer = response.getWriter();writer.println("<h1>读取cookie信息成功~</h1>");writer.flush();writer.close();}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}
}
4、访问 ReadCookie.java, 使用浏览器抓包分析 读取 Cookie 的底层机制。
说明:
- 不同会话,jsessionid 不同;
- 不同的浏览器,可能看到的cookie信息不完全相同;
- 一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称(NAME)和设置值(VALUE);
- 一个WEB站点可以给一个浏览器发送多个Cookie,一个浏览器也可以存储多个WEB站点提供的Cookie;
- cookie的总数量没有限制,但是每个域名的COOKIE数量和每个COOKIE的大小是有限制的(不同的浏览器限制不同,知道即可),Cookie不适合存放数据量大的信息;
- 使用 setMaxAge(0) 手动删除 Cookie时,需要使用 setPath 方法指定 Cookie 的路径,且该路径必须与创建 Cookie 时的路径保持一致;
- 注意:如果存放中文的cookie,默认报错,可以通过URL编码和解码来解决,不建议存放中文的cookie信息;
session
为什么需要?
- 不同的用户登录网站后,不管该用户浏览该网站的哪个页面,都可显示登录人的名字,还可以随时去查看自己的购物车中的商品, 是如何实现的?
- 也就是说,一个用户在浏览网站不同页面时,服务器是如何知道是张三在浏览这个页面,还是李四在浏览这个页面?
是什么?
Session 是服务器端技术
- 当用户打开浏览器,访问 Web 服务器的资源【不是HTML,CSS,图片等静态资源】时,服务器就会在内存(在服务端)为该浏览器分配一个 session 对象,该 session 对象被这个浏览器独占。
- 由于 session 为各个用户浏览器独享,所以用户在访问服务器的不同页面时,可以从各自的 session 中读取/添加数据, 从而完成相应任务;
- Session 对象也是一种域对象,它可以对属性进行操作,进而实现会话中请求之间的数据通讯和数据共享;
存储结构为 ConcurrentHashMap, 可以把 session 看作是一容器类似 HashMap,有两列(K-V),每一行就是 session 的一个属性。每个属性包含有两个部分,一个是该属性的名字(String),另外一个是它的值(Object)。
应用场景
- 网上商城中的购物车
- 保存登录用户的信息
- 将数据放入到 Session 中,供用户在访问不同页面时,实现跨页面访问数据
- 防止用户非法登录到某个页面。。。
工作原理
- 当客户端第一次请求会话对象时,服务器会创建一个 Session 对象,并为该 Session 对象分配一个唯一的 SessionID(用来标识这个 Session 对象);
- 服务器将 SessionID 以 Cookie(Cookie 名称为:“JSESSIONID”,值为 SessionID 的值)的形式发送给客户端浏览器;
- 客户端浏览器再次发送 HTTP 请求时,会将携带 SessionID 的 Cookie 随请求一起发送给服务器;
- 服务器从请求中读取 SessionID,然后根据 SessionID 找到对应的 Session 对象。
说明
【1】session 对象的存活时间
session 对象也可看做是一个容器/集合,默认存在时间为 30min。【指Session 对象在服务器中驻留一段时间后没有被使用,就会被销毁】
设置方式
- 1. 使用 <session-config> 元素
- 2. 调用 setMaxInactiveInterval() 方法
在 web.xml 中,使用 <session-config> 及其子元素 <session-timeout> 可以配置 Session 的默认过期时间,代码如下。<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"><!--设置session的过期时间--><session-config><session-timeout>10</session-timeout></session-config>
</web-app><session-timeout> 元素用来指定默认 Session 过期时间,以分钟为单位,该元素值必须为整数。
<session-timeout> 元素的值为零或负数,表示 Session 永远不会过期。
//设置会话的过期时间
//以秒为单位,零和负数表示会话永远不会过期
request.getSession().setMaxInactiveInterval(100);public int getMaxInactiveInterval()获取 Session 的超时时间
public void invalidate() 让当前 Session 会话立即无效
【2】 Cookie对象
流程中的 Cookie 是容器自动生成的,它的 maxAge 属性取值为 -1,表示仅当前浏览器有效。
浏览器关闭时,对应的 Session 并没有失效,但此时与此 Session 对应的 Cookie 已失效,导致浏览器无法再通过 Cookie 获取服务器端的 Session 对象。
同一浏览器的不同窗口共享同一 Session 对象,但不同浏览器窗口之间不能共享 Session 对象。
相关API
Session 对象由服务器创建,通过 HttpServletRequest.getSession() 方法可以获得 HttpSession 对象,例如:
- //获取session对象
- HttpSession session=request.getSession();
HttpSession 接口定义了一系列对 Session 对象操作的方法,如下表。
返回值类型 | 方法 | 描述 |
---|---|---|
long | getCreationTime() | 返回创建 Session 的时间。 |
String | getId() | 返回获取 Seesion 的唯一的 ID。 |
long | getLastAccessedTime() | 返回客户端上一次发送与此 Session 关联的请求的时间。 |
int | getMaxInactiveInterval() | 返回在无任何操作的情况下,Session 失效的时间,以秒为单位。 |
ServletContext | getServletContext() | 返回 Session 所属的 ServletContext 对象。 |
void | invalidate() | 使 Session 失效。 |
void | setMaxInactiveInterval(int interval) | 指定在无任何操作的情况下,Session 失效的时间,以秒为单位。负数表示 Session 永远不会失效。 |
生命周期
Session 的生命周期指的是 :客户端/浏览器同一个会话两次请求之间最大间隔时长,而不是累积时长。
- 值为正数,设定Session的超时时长
- 值为负数,表示永不超时
- 即当客户端访问了自己的 session,session 的生命周期将从 0 开始重新计算;
- 底层: Tomcat 用一个线程来轮询会话状态,如果某个会话的空闲时间超过设定的最大值,则将该会话销毁;
- 如果你在 session 没有过期的情况下,操作 session, 则会重新开始计算生命周期;而 session 是否过期,是由服务器来维护和管理
包括
- 1、Session对象的创建:在容器第一次调用 request.getSession() 方法时创建。
- 2、Session对象的销毁
- Session 过期;
- 调用 session.invalidate() 方法,手动销毁 Session;
- 服务器关闭或者应用被卸载
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;public class CreateSession2 extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("CreateSession2 被调用");//创建sessionHttpSession session = request.getSession();System.out.println("CreateSession2 sid= " + session.getId());//设置生命周期为 60ssession.setMaxInactiveInterval(60);session.setAttribute("u", "jack");//回复一下浏览器response.setContentType("text/html;charset=utf-8");PrintWriter writer = response.getWriter();writer.println("<h1>创建session成功, 设置生命周期60s</h1>");writer.flush();writer.close();}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}
}
区别
不同点 | Cookie | Session |
---|---|---|
存储位置不同 | Cookie 将数据存放在客户端浏览器内存中或硬盘上。 | Session 将数据存储在服务器端。 |
大小和数量限制不同 | 浏览器对 Cookie 的大小和数量有限制。 | Session 的大小和数量一般不受限制。 |
存放数据类型不同 | Cookie 中保存的是字符串。 | Session 中保存的是对象。 |
安全性不同 | Cookie 明文传递,安全性低,他人可以分析存放在本地的 Cookie 并进行 Cookie 欺骗。 | Session 存在服务器端,安全性较高。 |
对服务器造成的压力不同 | Cookie 保存在客户端,不占用服务器资源。 | Session 保存在服务端,每一个用户独占一个 Session。若并发访问的用户十分多,就会占用大量服务端资源。 |
跨域支持上不同 | Cookie 支持跨域名访问。 | Session 不支持跨域名访问。 |
请求的转发和重定向
转发
为什么用?
在实际开发中,往往业务比较复杂,需要在一次请求中,使用到多个 Servlet 完成一个任务(Servlet 链, 流水作业) 。【而 Serlvet 对象无法直接调用其他 Servlet 的 service() 方法】
是什么?
请求转发属于服务器行为,指一个 web 资源收到客户端请求后,通知服务器去调用另外一个 web 资源进行处理。在Servlet中,Servlet(源组件)先对客户请求做一些预处理操作,然后把请求转发给其它Servlet(目标组件)来完成包括生成响应结果在内的后续操作。
javax.servlet 包中定义了一个 RequestDispatcher 接口,RequestDispatcher 对象由 Servlet 容器创建,用于封装由路径所标识的 Web 资源,利用 RequestDispatcher 对象的 forward 方法可以把请求转发给其它的 Web 资源。
RequestDispatcher 对象的创建
- 调用 ServletContext 的 getRequestDispatcher(String path) 方法,参数 path 指定目标资源的路径,必须为绝对路径;
- 调用 ServletRequest 的 getRequestDispatcher(String path) 方法,参数 path 指定目标资源的路径,可以为绝对路径,也可为相对路径;
RequestDispatcher 的相关API如下:
返回类型 | 方法 | 描述 |
void | forward(ServletRequest request,ServletResponse response) | 用于将请求转发给另一个 Web 资源。该方法必须在响应提交给客户端之前被调用,否则将抛出 IllegalStateException 异常 |
void | include(ServletRequest request,ServletResponse response) | 用于将其他的资源作为当前响应内容包含进来 |
特点:
请求转发不支持跨域访问,只能跳转到当前应用中的资源。
- 可以转发到 WEB-INF 目录下(后面做项目使用),不能访问当前WEB 工程外的资源;
请求转发之后,浏览器地址栏中的 URL 不会发生变化,因此浏览器不知道在服务器内部发生了转发行为,更无法得知转发的次数。
- 地址会保留在第 1 个 servlet 的 url;如果你刷新页面,会再次发出请求(并且会带数据);所以在支付页面情况下,不要使用请求转发,否则会造成重复支付。
参与请求转发的 Web 资源之间共享同一 request 对象和 response 对象。在同一次HTTP 请求中,进行多次转发,仍然是一次 HTTP 请求;因为 forward() 方法会先清空 response 缓冲区,因此只有转发到最后一个 Web 资源时,生成的响应才会被发送到客户端。
代码实现1、开发一个登录页面2、创建src\com\hspedu\servlet\request\CheckServlet.java3、创建src\com\hspedu\servlet\request\ManageServlet.java4、测试注意看浏览器的请求次数和数据通信情况
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>登录</title>
</head>
<body>
<form action="http://localhost:8080/servlet/computerServlet" method="post">u: <input type="text" name="username"><br><input type="submit" value="登录">
</form>
</body>
</html>import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;public class CheckServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("CheckServlet 被调用..");//根据用户名来确定该用户是什么身份String username = request.getParameter("username");//注意:如果是同一个request对象(请求转发),那么可以在不同的servlet中,是getParameterif ("tom".equals(username)) {//分配request.setAttribute("role", "管理员");} else {request.setAttribute("role", "普通用户");}//获取分发器RequestDispatcher对象
// 1. /manageServlet写的是 要转发的servlet的url
// 2. / 会被解析成 /servlet
// 3. forward(request, response) 表示把当前servlet的request对象和response对象,传递给下一个servlet使用RequestDispatcher requestDispatcher =request.getRequestDispatcher("/manageServlet");requestDispatcher.forward(request, response);}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}
}import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;public class ManageServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("ManageServlet 被调用..");String username = request.getParameter("username");String role = (String) request.getAttribute("role");//输出信息response.setContentType("text/html;charset=utf-8");PrintWriter writer = response.getWriter();writer.print("用户名: " + username + "<br/>");writer.print("角色 : " + role);writer.flush();writer.close();}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}
}
重定向
重定向属于客户端行为。
请求重定向指的是服务器端接收到客户端的请求之后,会给客户端返回了一个临时响应头,这个临时响应头中记录了客户端需要再次发送请求(重定向)的 URL 地址,客户端再次收到了地址之后,会将请求发送到新的地址上,这就是请求重定向。
响应重定向是通过HttpServletResponse对象sendRedirect(“路径”)的方式实现是,是服务器通知浏览器,让浏览器去自主请求其他资源的一种方式。
- 本质上是两次 HTTP 请求,对应两个 request 对象和两个 response 对象
- 不能重定向到 /WEB-INF 下的资源,可以重定向到Web 工程以外的资源, 比如 到 www.baidu.com ;
最佳应用场景
- 网站迁移,比如原域名是 www.hsp.com 迁移到 www.hsp.cn ,但是百度抓取的还是原来网址.
如何实现:
方式1__推荐方式: response.sendRedirect("/hiServlet/servlet02")
方式2:
//1.设置响应状态码302,表示重定向;
//2.设置响应头,说明新的地址在哪里
response.setStatus(302);
response.setHeader("Location","/hiServlet/servlet02")
原理说明
- 用户在浏览器中输入 URL,请求访问服务器端的 Web 资源。
- 服务器端的 Web 资源返回一个状态码为 302 的响应信息;该响应的含义为:通知浏览器再次发送请求,访问另一个 Web 资源(在响应信息中提供了另一个资源的 URL)。
- 当浏览器接收到响应后,立即自动访问另一个指定的 Web 资源。
- 另一 Web 资源将请求处理完成后,由容器把响应信息返回给浏览器进行展示。
应用案例:
需求:演示请求重定向的使用:当访问DownServlet下载文件,重定向到DownServletNew下载文件。
1、创建src\com\hspedu\servlet\response\DownServlet.java
2、创建src\com\hspedu\servlet\response\DownServletNew.java
3、在 web.xml 中完成 servlet 配置
4、测试import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;public class DownServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// System.out.println("DownServlet 被调用");// response.setContentType("application/x-tar;charset=utf-8");// PrintWriter writer = response.getWriter();// writer.print("hi");// writer.flush();// writer.close();//完成了自己业务//发出请求重定向-> DownServletNew//1. sendRedirect 本质就会 返回 302 状态码 Location: /servlet/downServletNew//2. 因此 302和 /servlet/downServletNew 是浏览器解析,而不是服务器//3. 浏览器在解析 /servlet/downServletNew => http://localhost:8080/servlet/downServletNew//4. 动态获取到application contextString contextPath = getServletContext().getContextPath();System.out.println("contextPath= " + contextPath);//response.sendRedirect("/servlet/downServletNew");response.sendRedirect(contextPath + "/downServletNew");//response.sendRedirect("http://www.baidu.com");//第二种重定向的写法// System.out.println("第二种方式重定向...");// response.setStatus(302); //设置http响应的状态码// //设置http响应的 Location: /servlet/downServletNew// response.setHeader("Location", "/servlet/downServletNew");}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request,response);}
}import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class DownServletNew extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("DownServletNew 被调用");response.setContentType("text/html;charset=utf-8");PrintWriter writer = response.getWriter();writer.print("ok");writer.flush();writer.close();}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request,response);}
}<servlet><servlet-name>DownServlet</servlet-name><servlet-class>com.hspedu.servlet.response.DownServlet</servlet-class></servlet><servlet-mapping><servlet-name>DownServlet</servlet-name><url-pattern>/downServlet</url-pattern></servlet-mapping><servlet><servlet-name>DownServletNew</servlet-name><servlet-class>com.hspedu.servlet.response.DownServletNew</servlet-class></servlet><servlet-mapping><servlet-name>DownServletNew</servlet-name><url-pattern>/downServletNew</url-pattern></servlet-mapping>
比较
请求转发和重定向的区别
● 对于客户端浏览器来说,转发是一个请求,重定向是两个请求;
● 转发浏览器地址栏不变化,重定向会变成转发后的 URL ;
● 转发只能在一个项目内,而重定向没有限制,可以重定向到任意网(也就是跨域),如京东、淘宝等 ;
● 转发可以使用 request 域传递数据,而重定向不能。因为转发是一个请求,重定向是两个请求;
● 转发只有一个请求,原来是什么请求方式就是什么方式;而重定向两个请求,第一个可能为 post 可能为 get ,但是第二个请求一定是 get 。
区别 | 转发 | 重定向 |
---|---|---|
浏览器地址栏 URL 是否发生改变 | 否 | 是 |
是否支持跨域跳转 | 否 | 是 |
请求与响应的次数 | 一次请求和一次响应 | 两次请求和两次响应 |
是否共享 request 对象和 response 对象 | 是 | 否 |
是否能通过 request 域对象传递数据 | 是 | 否 |
速度 | 相对要快 | 相对要慢 |
行为类型 | 服务器行为 | 客户端行为 |
其他
请求转发和重定向的路径问题
请求路径
@WebServlet(urlPatterns = "/Servlet1.do")
//@WebServlet(urlPatterns = "/c/c2/servlet1.do")public class Servlet1 extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {/*** 请求转发的路径写法* 相对基准路径:相对于当前Servlet本身的位置,urlPattern决定了位置* 绝对基准路径:永远是以项目为基准路径(不允许跨服务,所以绝对路径只能是本服务内的资源)*//*相对路径访问a1.html*///RequestDispatcher requestDispatcher = req.getRequestDispatcher("a/a2/a1.html");/*urlpatterns会影响相对路径*///RequestDispatcher requestDispatcher = req.getRequestDispatcher("../../a/a2/a1.html");/*绝对路径访问a1*/RequestDispatcher requestDispatcher = req.getRequestDispatcher("/a/a2/a1.html");requestDispatcher.forward(req,resp);}
}
请求转发路径总结:
1. 以"/"开头的路径是绝对路径,不以"/"开头是相对路径;
2. 绝对路径以当前项目名(或叫部署名)为根路径,"/"后不需要写当前项目名;
3. ../代表向上一层的路径;
4. Servlet的相对路径是相对于url-pattern中的路径,是虚拟的路径。
重定向路径
//@WebServlet(urlPatterns = "/c/c2/servlet2.do")
@WebServlet(urlPatterns = "/Servlet2.do")
public class Servlet2 extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 请求重定向到a1.html/*** 相对路径 相对于urlPatterns定义的路径* 绝对路径 :以项目部署路径为基准路径 (webapps)* 请求重定向的绝对路径中,要加项目部署名,除非当前项目没有给定部署名**/// resp.sendRedirect("../../a/a2/a1.html");//resp.sendRedirect("a/a2/a1.html");ServletContext servletContext = this.getServletContext();String contextPath = servletContext.getContextPath();// /ServletModule5resp.sendRedirect(contextPath+"/a/a2/a1.html");}
}
请求重定向路径总结:
1. 以"/"开头的路径是绝对路径,不以"/"开头是相对路径;
2. 绝对路径以当前项目所在目录(Tomcat的webapps下)为根路径,绝对路径后需要写当前项目部署名;
3. ../代表向上一层的路径;
4. Servlet的相对路径是相对于url-pattern中的路径,是虚拟的路径;
路径的使用和记忆建议:
建议在url-pattern中,不要书写没有必要的多层次路径如:"/c/c2" ,因为这会影响请求转发和重定向的相对路径写法;
绝对路径在书写时,只有请求转发不需要写项目部署名,页面(如超链接)上和重定向的绝对路径都需要写项目的部署名;
相对路径在使用时,无论是页面(如超链接)还是请求转发还是请求重定向都不需要项目名;