目录
一、关于base标签
1.引入 :
2.介绍 :
3.实例 :
4.细节 :
二、Cookie的引入
1.会话技术 :
1° 什么是会话技术?
2° 会话技术用于解决什么问题?
2.Cookie介绍
1° Cookie有什么用?
2° Cookie通讯机制
三、Cookie的基本使用
1.创建Cookie对象并保存到浏览器 :
2.服务器端读取浏览器保存的Cookie :
四、Cookie的应用实例
1.关于“JSESSIONID”的说明 :
2.读取指定Cookie :
3.修改Cookie :
五、Cookie的生命周期
1.基本介绍 :
2.setMaxAge(int expiry)方法 :
3. 应用实例 :
六、Cookie有效路径
1.规则 :
2.应用实例 :
有两个html文件,位置如下 :
demo1.html代码如下 :
demo1
点我到demo2.html
demo2.html代码如下 :
demo2
点我去demo1.html~
运行效果如下GIF图 :
2° 当Web工程中的文件数目较多时,频繁地使用相对路径会造成“工程路径复杂”的问题。
解决方法——如果需要指定页面相对路径参考的的路径,可以使用base标签来指定。
1° base标签是 HTML 语言中的基准网址标记,是一个单标签,位于网页头部文件的head标签内 。 2° 一个页面最多只能使用一个 base 元素,用来提供一个指定的默认目标,是一种表达路 径和连接网址的标记。3° 常见的 url 路径形式分别有相对路径与绝对路径,如果 base 标签指定了目标, 浏览器 将通过这个目标来解析当前文档中的所有相对路径 ,包括的标签有( a , img , link, form )4° 也就是说,浏览器解析时会在路径前加上 base 给的目标,而页面中的相对路径也都转 换成了绝对路径。使用了 base 标签就应带上 href 属性和 target 属性。
demo1.html代码如下 :
demo1
点我到demo2.html
demo2.html代码如下 :
demo2
点我去demo1.html~
运行结果 :
1°
标签也可以应用于“请求转发”和“请求重定向”。PS : 标签的href属性值最后加不加/,对实际作用效果影响很大。 2° 实际开发中,使用“绝对路径”。
3° 关于URL开头的"/",若/被服务器端解析,/会被解析成" /Web工程名/ ";若/被浏览器端(客户端)解析,/会被解析成" http://IP[域名]:port/ "。
PS : 如果服务器端解析的URL开头没写/,默认隐含/;如果浏览器端解析的URL开头没有/,默认会以浏览器地址栏中的" http://IP[域名]:port/Web工程目录 "来和访问的资源进行拼接。
4° 在JavaWeb中,URL路径最后带"/" 和 不带"/"是两回事;URL最后带/表示访问的是一个路径,URL最后不带/表示访问的是一个资源。
5° 请求重定向中,resp.sendRedirect("URL"); 语句虽然是在服务器端被执行,但解析URL是在浏览器端进行的。PS : 推荐使用this.getServletContext.getContextPath()方法来动态地获取Web工程路径,可以使URL配置更加灵活。
会话可简单理解为:用户打开一个浏览器,点击多个超链接,访问Web服务器的多个web资源,然后关闭浏览器,整个过程称之为一个会话。会话是在浏览器端(客户端)和服务器端之间进行的。
每个用户在使用浏览器与服务器进行会话的过程中,不可避免各自会 产生一些数据 ,服 务器会设法为 每个用户 保存各自的这些数据。eg : 多个用户分别点击购物网站的超链接,通过一个购物servlet各自购买了一个商品,服务器应该想办法把每一个用户购买的商品的信息保存在各自的地方,以便于这些用户点结账时,调用结帐servlet,结帐servlet 可以得到用户各自购买的商品信息为用户结帐。
Cookie是客户端技术;服务器把每个用户的数据以cookie的形式写给用户各自的浏览器,当用户使用浏览器再去访问服务器中的web资源时,就会带着各自的数据去。这样,web资源处理的就是用户各自的数据了。
示意图如下 :
1> Cookie是服务器在客户端保存的用户相关信息,比如登录名,浏览记录等非敏感信息, 就可以通过cookie方式来保存.
2> Cookie信息数据量并不大,服务器端在需要的时候可以从客户端/浏览器读取(遵循HTTP协议;req.getCookies()方法)。浏览器向服务器发送HTTP请求时,会在请求包中自动携带当前服务器域名下对应的Cookie。再次注意,Cookie是保存在浏览器端的。
CookieBaseServlet类代码如下 :
package intro;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @author : Cyan_RA9
* @version : 21.0
*/
public class CookieBaseServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("CookieBaseServlet's doPost is invoked");
//1.创建一个Cookie对象(key是Cookie的名字,唯一)
//可以创建多个Cookie对象
Cookie cookie = new Cookie("username", "Cyan");
Cookie cookie2 = new Cookie("platform", "CSDN");
//2.将创建好的Cookie对象发送给浏览器,浏览器会将收到的Cookie信息进行保存
resp.setContentType("text/html; charset=utf-8");
resp.addCookie(cookie);
resp.addCookie(cookie2);
PrintWriter writer = resp.getWriter();
writer.print("创建Cookie成功,已保存!
");
writer.flush();
writer.close();
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
}
web.xml配置文件如下 :
CookieBaseServlet
intro.CookieBaseServlet
CookieBaseServlet
/cbServlet
运行效果 : (如下GIF图)
HTTP响应包分析 :
浏览器端Cookie存储 :
ReadCookiesServlet类代码如下 :
\package intro;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet(urlPatterns={"/readServlet", "/read"})
public class ReadCookiesServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("ReadCookiesServlet's doPost is invoked~\n");
//获取浏览器端保存的Cookie信息
Cookie[] cookies = req.getCookies();
if (cookies != null && cookies.length != 0) {
for (Cookie cookie : cookies) {
System.out.println("cookie's name = " + cookie.getName() +
",cookie's value = " + cookie.getValue());
}
}
//给浏览器回送消息
resp.setContentType("text/html; charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.print("收到!
");
writer.flush();
writer.close();
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
}
运行效果(如下GIF图 ) :
通过抓包,可以找到HTTP请求包中的Cookie请求头,如下图所示 :
浏览器保存的Cookie信息中,JSESSIONID用于唯一标识不同的会话;不同会话,JSESSIONID不同。
当浏览器向服务器发送HTTP请求时,服务器会从HTTP请求头的Cookie信息中找到JSESSIONID,根据JSESSIONID的值来判断当前会话的客户端是哪个。
先编写一个可以获取Cookie信息的工具类CookieUtils.
CookieUtils类代码如下 :
package instance;
import jakarta.servlet.http.Cookie;
/**
* readCookieByName方法 : 返回指定name的Cookie
*/
public class CookieUtils {
public static Cookie readCookieByName(String name, Cookie[] cookies) {
if (null == name || "".equals(name) || null == cookies || cookies.length == 0) {
return null;
}
for (Cookie cookie : cookies) {
if (name.equals(cookie.getName())) {
return cookie;
}
}
return null;
}
}
编写一个测试类;ReadSpecificCookieServlet类代码如下 :
package instance;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet(urlPatterns={"/readSpecificCookie"})
public class ReadSpecificCookieServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Cookie cookie = new Cookie("color", "pink");
resp.addCookie(cookie);
Cookie[] cookies = req.getCookies();
Cookie color = CookieUtils.readCookieByName("color", cookies);
if (null != color) {
System.out.println("Cookie's name = " + color.getName() +
", Cookie's value = " + color.getValue());
} else {
System.out.println("Can't find that Cookie with this specific name!");
}
resp.setContentType("text/html; charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.print("The task of getting specific is completed~
");
writer.flush();
writer.close();
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
}
运行效果如下 : (GIF)
修改浏览器端保存的Cookie信息有两种方式。
方式一 : 新创建一个同名的Cookie对象,然后通过resp.addCookie(cookie); 方法,实现Cookie新值对旧值的覆盖。
方式二 : 先获取到要修改的Cookie对象,通过cookie.setValue("..."); 方法,修改Cookie的值,然后再通过resp.addCookie的方式,以HTTP响应的方式将修改后的Cookie打回给浏览器。
ModifyCookieServlet类代码如下 :
package instance;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet(urlPatterns={"/modifyCookie"})
public class ModifyCookieServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//方式一 :
Cookie cookie_username = new Cookie("username", "Cyan_RA9");
if (cookie_username != null) {
resp.addCookie(cookie_username);
}
//方式二 :
Cookie[] cookies = req.getCookies();
String cookieName = "color";
Cookie cookie = CookieUtils.readCookieByName(cookieName, cookies);
if (cookie != null) {
cookie.setValue("bluish_green"); //Cookie信息中不能包含空格
resp.addCookie(cookie);
} else {
System.out.println("当前访问服务器端的浏览器,没有保存该Cookie信息!");
}
//在服务器端遍历Cookies
for (Cookie c : cookies) {
System.out.println("cookie's name = " + c.getName() +
", cookie's value = " + c.getValue() + "\n");
}
resp.setContentType("text/html; charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.print("The task of updating Cookie is completed~
");
writer.flush();
writer.close();
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
}
运行效果 : (GIF) (请求头抓包时,手贱刷新了一下
Cookie的生命周期指的是如何管理Cookie的销毁,即 Cookie 什么时候被销毁(删除)。
public void setMaxAge(int expiry) : 该方法可以设置cookie的最大生存时间,以秒为单位。
Δ注意事项 :
1° expiry为正值,表示cookie将在经过该值对应的秒数后过期。即,该值是cookie过期的最大生存时间,而不是cookie 的当前生存时间。
PS : cookie过期/失效,指的是浏览器在访问服务器时,HTTP请求头中不会携带过期的cookie信息。浏览器根据cookie创建的时间,计时到expiry,就认为该cookie无效。
2° expiry为负值,表示cookie不会被持久存储,将在Web会话的浏览器退出时被删除。默认情况下,expiry = -1(会话级别的生命周期)。
3° expiry = 0,表示令cookie立刻失效,立刻被"删除"。(销毁)
CookieServletLife类代码如下 :
package lifetime;
import instance.CookieUtils;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet(urlPatterns={"cookieLife"})
public class CookieLifeServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.创建测试的cookie
Cookie newCookie1 = new Cookie("test1", "haha");
Cookie newCookie2 = new Cookie("test2", "NB");
//2.设置cookie生命周期
newCookie1.setMaxAge(10); //10s后
newCookie2.setMaxAge(0); //直接
Cookie[] cookies = req.getCookies();
Cookie test1 = CookieUtils.readCookieByName("test1", cookies);
Cookie test2 = CookieUtils.readCookieByName("test2", cookies);
System.out.println("test1 = " + test1);
System.out.println("test2 = " + test2);
//3.别忘了将cookie信息发送给浏览器
if (null != test1) {
resp.addCookie(newCookie1);
} else {
System.out.println("没有找到该cookie__test1.");
}
if (null != test2) {
resp.addCookie(newCookie2);
} else {
System.out.println("没有找到该cookie__test2.");
}
//4.回显信息给浏览器
resp.setContentType("text/html; charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.print("The task of testing cookie's lifetime is completed~
");
writer.flush();
writer.close();
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
}
运行效果 :(GIF)
Cookie有效路径,指的是浏览器端保存的Cookie的path属性。如下图所示 :
Cookie 的 path 属性可以有效的过滤哪些Cookie会被携带在HTTP请求头中发送给服务器,哪些不会。
path属性是通过请求的URL来进行有效的过滤,规则如下——
①若cookie未设置path属性,默认是"/Application context",即Web工程路径。
②当请求的URL是Web工程路径的子路径时,即比Web工程路径更具体的路径,eg : /Cookie_Demo/d1,也会携带父路径的Cookie信息。(集合的包含关系)
③cookie.setPath("......"); 方法用于设置该cookie的path属性。
CookiePathServlet类代码如下 :
package path;
import instance.CookieUtils;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
若没有采用web.xml配置文件的方式配置URL,
就一定不要忘记配置@WebServlet注解
*/
@WebServlet(urlPatterns={"/cookiePath"})
public class CookiePathServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Cookie cookie1 = new Cookie("fruit", "grape");
/*
也可以通过req.getContextPath来获取工程路径
*/
cookie1.setPath(req.getContextPath());
Cookie cookie2 = new Cookie("animal", "cat");
cookie2.setPath(req.getContextPath() + "/d1");
resp.addCookie(cookie1);
resp.addCookie(cookie2);
resp.setContentType("text/html; charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.print("Check the cookies inside the HTTP-request-bag.
");
writer.flush();
writer.close();
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
}
运行效果 : (GIF)
1° 一个Cookie只能标识一种信息,它至少含有一个标识该信息的NAME和VALUE。PS:Cookie的name和value都是String类型。
2° 一个WEB站点可以给一个浏览器发送多个Cookie,一个浏览器也可以存储多个WEB站点提供的Cookie。
3° cookie的总数量没有限制,但是每个域名下的cookie数量和每个cookie的大小是有限制的(不同的浏览器一般限制不同,了解即可);总之一句话,Cookie不适合存放数据量大的信息。
4° 注意,删除cookie时,path必须一致,否则不会删除成功。
5° 可以通过 String string = URLEncoder.encode("string", "utf-8"); 方法来设置指定value的编码。然后再通过Cookie cookie = new Cookie("key", string); 来创建指定了value编码格式的Cookie对象。最后,通过resp.addCookie(cookie); 即可将cookie信息发送给浏览器。
如果需要对中文Cookie进行解码,使用String value = URLDecoder.decode(value, "utf-8"); 方法。