天的论题是cookie的作用及cookie 的分类。首先cookie是追踪访问者行为中的重要一环,在所有的检测系统和追踪工具中想是不可或缺的。cookie最初的作用并不是用来追踪访问者行为,而是网站用来记录访问者的用户信息、历史记录、访问偏好,以及判定老访客的登录状态,并且通过这世信息提升访问者在网站的使用体验。
例如:新访客并不需要每次都以用户名和密码进行登录操作,在访问淘宝时,可以看到上次浏情的商品信息。这些都是依靠Cookie中存储的信息如果将浏览器中所有Cookie都清空,再访问经常光顾的网站时就会发现Cookie有多重要了。
cookies分为第一方Cookie和第三方Cookie,这两类Cookie都是网站保存在用户电脑上的一个文件,它们都由某个特定的域创建,并且只能被这个域访问。我们可以通过浏览器或第三方工具来查看网站对我们设置的Cookie情况,它们之间的区别归根结底在于是什么域名创建了 cookies。
第一方 cookie 指的是由网络用户访问的域创建的 cookie。例如:当用户通过网络浏览器点击我博客rrdaj.com 时,浏览器会在第一个页面中发送一个网页请求,这个过程需要用户直接与 rrdaj.com 互动。这样网络浏览器随后就将此数据文件保存到“rrdaj.com”域名下的用户计算机上。
大多数网页浏览器都支持第一方 cookies。
为什么?
因为如果你禁用第一方 cookies,当你浏览网页从一页跳到另一页的时候,网站无法跟踪你的活动。再比如:每次你从购物网站的其他页面向购物车添加一些东西,它就会被视为一个新的动作而没有被记录下来,这样你将无法在同一交易中在线购买多个商品了。
第三方cookie是建立在别的域名不是你访问的域名(地址栏中的网址), 比如:广告网络商就是最常见的第三方 cookies 的来源,他们用它们在多个网站上追踪用户的行为,当然这些活动可以用来调整广告。此外图像、 JavaScript 和 iframe 通常也会导致第三方 cookies 的生成。
像前不久的GDPR,用户就不会像第一方cookie那样对第三方 cookies 那么友好了,有的用户就不会对它进行买单。
为什么?
因为许多人认为这是对他们隐私的侵犯,是对他们数字安全的威胁。(例如:下图baidu.com就是属于第三方的cookie记录)
对于第三方 cookies 来说,最常见的用法是在不同领域去跟踪用户,尤其是广告商。在识别和跟踪单个域名的用户时,第一方 cookie 非常有用。
然而,有时候你想要在多个领域跟踪用户,比如:
(1)你经营着一个拥有多个子品牌的大品牌,如果你是一家比较大的零售商或食品饮料公司或者是电商,你可能会在主品牌下拥有多个品牌,例如:大家都熟悉的服饰品牌Gap旗下就有好几个子品牌(GAP、Banana Republic、Old Navy、Piperlime、Athleta),每个子品牌都有自己的域名。
因此也有自己的第一方cookie,这意味着主品牌www.gap.com母公司不能使用第一方 cookies 来识别其他子品牌网站上的用户了。这样第三方cookie就起作用了,可以用它去追踪子品牌,比如:ab-inbev.com下的用户行为,方便做大数据管理。
(2)第二种情况就是我上面说的广告商,这个好理解,比如:我们熟知的Google Adsense ,通过第三方cookie,谷歌可以通过他们去识别这些1400多万个网站(可能还有更多)的用户信息,国内有很多广告联盟也是同样的道理。
因此,应对方法就出来了,一些用户使用像 AdBlock Plus 和 NoScript 这样的插件来阻止诸如广告和 JavaScript 之类的东西在网站上加载,从而阻止了第三方 cookies 的创建。更常见的是,或者他们使用配置他们的浏览设置,这样网页浏览器就会屏蔽或清除它们。
作者:该吃药了,公号:ISEOers(ID:iseo888)
本文由 @该吃药了原创发布于人人都是产品经理。未经许可,禁止转载
题图来自Unsplash,基于CC0协议
先要了解HTTP是无状态的Web服务器,什么是无状态呢?一次对话完成后下一次对话完全不知道上一次对话发生了什么。如果在Web服务器中只是用来管理静态文件还好说,对方是谁并不重要,把文件从磁盘中读取出来发出去即可。但是随着网络的不断发展,比如电商中的购物车只有记住了用户的身份才能够执行接下来的一系列动作。所以此时就需要我们无状态的服务器记住一些事情。
那么Web服务器是如何记住一些事情呢?既然Web服务器记不住东西,那么我们就在外部想办法记住,相当于服务器给每个客户端都贴上了一个小纸条。上面记录了服务器给我们返回的一些信息。然后服务器看到这张小纸条就知道我们是谁了。那么Cookie是谁产生的呢?Cookies是由服务器产生的。接下来我们描述一下Cookie产生的过程
浏览器第一次访问服务端时,服务器此时肯定不知道他的身份,所以创建一个独特的身份标识数据,格式为key=value,放入到Set-Cookie字段里,随着响应报文发给浏览器。
浏览器看到有Set-Cookie字段以后就知道这是服务器给的身份标识,于是就保存起来,下次请求时会自动将此key=value值放入到Cookie字段中发给服务端。
服务端收到请求报文后,发现Cookie字段中有值,就能根据此值识别用户的身份然后提供个性化的服务。
如何创建 Cookie
Servlet 程序中的代码:
protected void createCookie(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1 创建Cookie对象
Cookie cookie=new Cookie("key4", "value4");
//2 通知客户端保存Cookie
resp.addCookie(cookie);
//1 创建Cookie对象
Cookie cookie1=new Cookie("key5", "value5");
//2 通知客户端保存Cookie
resp.addCookie(cookie1);
resp.getWriter().write("Cookie创建成功");
}
Cookie创建成功!
服务器获取客户端的 Cookie 只需要一行代码:req.getCookies():Cookie[]
Cookie 的工具类:
public class CookieUtils {
/**
* 查找指定名称的 Cookie 对象
* @param name
* @param cookies
* @return
*/
public static Cookie findCookie(String name , Cookie[] cookies){
if (name==null || cookies==null || cookies.length==0) {
return null;
}
for (Cookie cookie : cookies) {
if (name.equals(cookie.getName())) {
return cookie;
}
}
return null;
}
}
Servlet 程序中的代码:
protected void getCookie(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Cookie[] cookies=req.getCookies();
for (Cookie cookie : cookies) {
// getName方法返回Cookie的key(名)
// getValue方法返回Cookie的value值
resp.getWriter().write("Cookie[" + cookie.getName() + "=" + cookie.getValue() + "] <br/>");
}
Cookie iWantCookie=CookieUtils.findCookie("key1", cookies);
// 如果不等于null,说明赋过值,也就是找到了需要的Cookie
if (iWantCookie !=null) {
resp.getWriter().write("找到了需要的Cookie");
}
}
方法一:
1、先创建一个要修改的同名(指的就是 key)的 Cookie 对象
2、在构造器,同时赋于新的 Cookie 值。
3、调用 response.addCookie( Cookie );
// 1 、先创建一个要修改的同名的 Cookie 对象
// 2 、在构造器,同时赋于新的 Cookie 值。
Cookie cookie=new Cookie("key1","newValue1");
// 3 、调用 response.addCookie( Cookie ); 通知 客户端 保存修改
resp.addCookie(cookie);
方法二:
1、先查找到需要修改的 Cookie 对象
2、调用 setValue()方法赋于新的 Cookie 值。
3、调用 response.addCookie()通知客户端保存修改
1 、先查找到需要修改的 Cookie 对象
Cookie cookie=CookieUtils.findCookie("key2", req.getCookies());
if (cookie !=null) {
// 2 、调用 setValue() 方法赋于新的 Cookie 值。
cookie.setValue("newValue2");
// 3 、调用 response.addCookie() 通知客户端保存修改
resp.addCookie(cookie);
}
在页面空白区域右键,然后点击检查:
Cookie 的生命控制指的是如何管理 Cookie 什么时候被销毁(删除)
setMaxAge()
正数,表示在指定的秒数后过期
负数,表示浏览器一关,Cookie 就会被删除(默认值是-1)
零,表示马上删除 Cookie
例:
protected void life3600(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
IOException {
Cookie cookie=new Cookie("life3600", "life3600");
cookie.setMaxAge(60 * 60); // 设置 Cookie 一小时之后被删除。无效
resp.addCookie(cookie);
resp.getWriter().write(" 已经创建了一个存活一小时的 Cookie");
}
protected void deleteNow(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
IOException {
// 先找到你要删除的 Cookie 对象
Cookie cookie=CookieUtils.findCookie("key4", req.getCookies());
if (cookie !=null) {
// 调用 setMaxAge(0);
cookie.setMaxAge(0); // 表示马上删除,都不需要等待浏览器关闭
// 调用 response.addCookie(cookie);
resp.addCookie(cookie);
resp.getWriter().write("key4 的 的 Cookie 已经被删除");
}
}
protected void defaultLife(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
IOException {
Cookie cookie=new Cookie("defalutLife","defaultLife");
cookie.setMaxAge(-1);// 设置存活时间
resp.addCookie(cookie);
}
Cookie 的 path 属性可以有效的过滤哪些 Cookie 可以发送给服务器。哪些不发。
path 属性是通过请求的地址来进行有效的过滤。
CookieA path=/工程路径
CookieB path=/工程路径/abc
请求地址如下:
http://ip:port/工程路径/a.html
CookieA 发送
CookieB 不发送
http://ip:port/工程路径/abc/a.html
CookieA 发送
CookieB 发送
例:
protected void testPath(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
IOException {
Cookie cookie=new Cookie("path1", "path1");
// getContextPath()===>>>> 得到工程路径
cookie.setPath( req.getContextPath() + "/abc" ); //===>>>> / 工程路径 /abc
resp.addCookie(cookie);
resp.getWriter().write(" 创建了一个带有 Path 路径的 Cookie");
}
login.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录页面</title>
</head>
<body>
<form action="http://localhost:8080/Test/loginServlet" method="get">
用户名:<input type="text" name="username" value="${cookie.username.value}"> <br>
密码:<input type="password" name="password"> <br>
<input type="submit" value="登录">
</form>
</body>
</html>
LoginServlet :
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username=req.getParameter("username");
String password=req.getParameter("password");
if ("kailong".equals(username) && "123456".equals(password)) {
//登录 成功
Cookie cookie=new Cookie("username", username);
cookie.setMaxAge(60 * 60 * 24 * 7);//当前Cookie一周内有效
resp.addCookie(cookie);
System.out.println("登录 成功");
} else {
// 登录 失败
System.out.println("登录 失败");
}
}
}
试验:
第一次登录:
点击登录后,控制台显示登录成功
然后我们关了浏览器再打开这个页面
再打开这个页面可以发现用户名已经存在,这就是cookie保存了用户名信息,然后这里设置的是Cookie有效期为一周,一周后该Cookie就失效了
公众号本文地址:一文了解Cookie
欢迎关注公众号:愚生浅末。
正式介绍cookie之前我们要先来说一说网络通讯协议
首先:什么是网络通讯协议?所谓协议一般就是甲乙双方沟通要遵循的规则与方式,那么通讯协议就是通讯双方要遵循的规则,网络通讯协议则是计算机双方传输数据所要遵循的协议,浏览网页时, 一般使用http或者https,而它们都是基于TCP/IP协议的。
在发送数据之前,都必须先在双方之间建立一条连接。在TCP/IP协议中,TCP 协议提供可靠的连接服务,连接是通过三次握手进行初始化的,如下图:
客户端要向服务器发送请求,首先会发送一个请求连接,这是第一次握手;
当服务器收到这个请求以后返回给客户端一条消息,这是第二次握手;
然后客户端再把确认消息发给服务器,这是第三次握手;
经过这三次握手客户端与服务器之间的连接就建立起来了。
就像打电话一样,客户端向服务器拨通电话,服务器接起电话,说了一句:“喂?”,然后客户端收到了这句“喂”,再跟服务器说一声“喂!”,连接就建立好了,可以愉快的通话了
建立连接需要经过三次握手,那数据传输结束以后呢?我们打电话事情说完了要挂掉电话要经历一个怎样的过程?可能对话是下面这样的:
A:“我挂了”
B:“好”
A:“拜拜”
B:“拜拜,我也挂了”
A:“好,拜拜”
B:“嗯嗯,拜拜,挂了”
A:“好,拜拜”
B:“拜拜”
有点搞笑 ,经过好多次消息确认好不容易才能把电话挂掉,但这并不是无聊,而是要互相确认对方是否真的已经准备断开连接了,那么我们的TCP/IP协议也会考虑到这一点,要断开连接会经过四次挥手,如下图:
数据传输结束时,客户端向服务器发送一条结束的消息,服务器收到消息后会马上返回给客户端确认消息,并随后发送一条“我也结束了”的消息,当客户端收到这条消息以后会响应给服务器确认消息,服务器收到这条确认消息以后就会关闭,而客户端则会等待两个单位时间之后关闭。注意这里客户端并不是立马关闭,而是会等带两个单位时间,为什么是两个单位时间呢?首先,所谓的单位时间指的是一次前后端数据传输所花费的时间,这里要等待两个单位时间是因为客户端要等数据发送到服务器以后确认收不到数据返回,这一来一去就是两个单位时间了,因为如果这个时候服务器并没有结束的话会再次给客户端响应,而客户端在两个单位时间后收不到响应则代表本次数据传输正式结束。
下面贴出两张动图:
这两张动图对于计算机专业的读者可以尝试探究,本文不做详细展开
HTTP协议, 使我们用户上网常见的协议, 简单的理解, 它是基于TCP/IP协议改造加工出来的,也就是说每一个http请求都会通过三次握手建立连接,传输数据, 然后四次挥手断开连接.
例如当你登录淘宝的时候, 你的浏览器跟淘宝服务器之间就行了 一个 http链接.
然后, 当首页数据加载完成, 链接就断开了.
这时服务就无法保存你的状态. 你浏览了什么商品? 购物车加了几个东西? 有没有关闭浏览器? 服务器统统不知道了
所以, 我们说:http协议是一种无状态协议,这里的无状态指的是无法保存状态,因为一旦数据传输结束连接就会断开,就无法获取一些状态了,这样设计的好处就是可以节约资源,需要的时候才发出请求,但是也会造成一些困扰,
尤其是关于身份验证. 用户在登录页面完成了登录,那么接下来就会回到首页或者其他页面进行操作,但问题是这个时候登录的这次http请求已经结束了,所以当完成页面跳转之后就取不到登录状态了,那怎么办?再登录一次?
当你反复使用http协议跟服务器建立链接的时候, 服务器怎么才能知道, 你是一个登录过的合法用户?? 为了解决这个问题, 出现了cookie技术.
cookie称之为会话跟踪技术,顾名思义,就是在一次会话中跟踪记录一些状态。首先,所谓的”会话“指的就是从浏览器打开一个网站到访问它的其他网页直到浏览器关闭的这个过程。
cookie就可以在一次会话从开始到结束的整个过程,全程跟踪记录客户端的状态(例如:是否登录、购物车信息、是否已下载、是否 已点赞、视频播放进度等等)。
cookie是服务器存储在客户端本地的一个文件. 它就好比服务器发给客户端的一个身份标识, 有了这个身份牌, 只要客户端随身携带这个身份牌. 服务器就能识别我们的身份了
其实, 如果是单纯的身份验证场景下, 前端开发是用不到cookie的
从服务器发送cookie给浏览器, 浏览器保存cookie, 到浏览器每次发送请求 ,携带着cookie文件, 这些事情浏览器全部都可以自己完成. 根本不需要我们前端开发人员参与.
但我们有时也会利用cookie, 在前端存储一些状态信息.
比如某个视频看到了32分15秒.
我们可以通过前端操作, 直接将这个数据保存在本地cookie文件中
下次打开网站, 我们再次读取这个信息
然后直接向服务器请求32分16秒的视频内容.
cookie的使用方式很简单 ,系统提供的只有一个属性 document.cookie,无论是存还是取或者其他操作都是通过这一个属性来完成(注:cookie是http协议下的技术,所以不要用file的方式打开本地html文件测试cookie,虽然由部分浏览器也在file协议下实现了cookie,但是不推荐这么做)。
首先,我们来看看如何存:
document.cookie='username=dary' // 存一条username为dary的cookie
但是如果当我们要存一条中文的cookie,比如:username=张三,在部分低版本浏览器就会遇到一些位置错误,这时就可以使用 encodeURIComponent 编码对中文进行编码:
document.cookie=`username=encodeURIComponent('大林')`
可以看到,中文内容已经被编码了,以后取得时候我们可以通过decodeURIComponent 方法进行解码,下文会提到
现在我们回头去看看上面我们存过的cookie,其中有Expires/max-Age选项,这一项指的就是cookie的有效期,我们可以看到是session,代表会话期,也就是默认的会话结束cookie失效,这时我们重启浏览器就看不到这条cookie了。
除了默认的会话过期我们还可以手动设置cookie的过期时间,比如:7天后过期
var date=new Date()
date.setDate(date.getDate() + 7)
document.cookie=`username=${encodeURIComponent('大林')};expires=${date.toUTCString()}`
我们可以看到过期时间已经是7天以后了,这里我用了toUTCString()方法转成了标准时区,所以比北京时间快8个小时,这时我们关闭浏览器再次打开,仍然可以看到这条cookie
我们来测试一下路径,随便进入项目中某一个目录或者新建一个目录,然后把一下代码放进去执行
document.cookie='username=dary'
我们可以看到,path不再是之前的 / 了,而是当前目录,这时我们再回到首页,你会发现,这条cookie不见了,因为外层时访问不了内层目录存的cookie的。
所以我们一般存cookie都会这么写:
document.cookie='username=dary;path=/'
不管当前目录是谁统一存根目录,这样项目中任意位置都可以访问这一条cookie,这就perfect 啦!
由此:我们可以封装一个存储cookie的方法如下:
/** 存一条cookie
* @param {string} key 要存的cookie的名称
* @param {string} value 要存的cookie的值
* @param {object} [options] 可选参数,过期时间和目录,如:{ path: '/', expires: 7 }存根目录7天过期的cookie
*/
function setCookie (key, value, options) {
var str=`${key}=${encodeURIComponent(value)}`
// 先判断options是否传进来了
if (options) {
// 如果传进来了再判断有哪个属性
if (options.path) {
// 路径拼接进去
str +=`;path=${options.path}`
}
if (options.expires) {
var date=new Date()
// 日期设置为过期时间
date.setDate(date.getDate() + options.expires)
str +=`;expires=${date.toUTCString()}`
}
}
document.cookie=str
}
现在我们掌握了如何存cookie,接下来看看怎么取吧
取cookie同样使用document.cookie这个属性:
console.log(document.cookie) // username=dary
但是如果我们在一个网站里存了多条cookie,这个时候得到的结果就是
console.log(document.cookie) // username=dary; age=18
多条cookie之间以; 隔开,注意:这里是分号和一个空格,这个对我们拆开每一条cookie非常重要。所以我们现在希望能把cookie每一条拆开,得到一个对象,这样就可以取得某一条cookie的值了,所以我们可以封装一个获取cookie的方法如下:
/** 获取某一条cookie
* @param {string} key 要获取的cookie的名称
* @retrun {string} 当前这条cookie的值
*/
getCookie (key) {
var str=document.cookie
var arr=str.split('; ')
var obj=new Object()
arr.forEach(item=> {
var subArr=item.split('=')
obj[subArr[0]]=decodeURIComponent(subArr[1])
})
return obj[key]
}
删除cookie的方式特别简单,我们只需要把cookie的过期时间设置为已经过去了的时间就行了,这个时候浏览器一看,诶?这条cookie不是已经过期了么?就只能把它删掉了 ,方法如下:
/** 删一条cookie
* @param {string} key 要删的cookie的名称
* @param {path} [path] 可选参数,要删的cookie的所在的路径,如果就是当前路径这个参数可以不传
*/
function removeCookie (key, path) {
var date=new Date()
date.setDate(date.getDate() - 1) // 过期时间设置为昨天
var str=`${key}='';expires=${date.toUTCString()}`
if (path) {
str +=`;path=${path}`
}
document.cookie=str
}
重新存一下把之前的覆盖掉就是修改了cookie了
最后附上一个cookie方法,既可以完成存也可以取,甚至可以删
*请认真填写需求信息,我们会在24小时内与您取得联系。