【GoWeb开发实战】Cookie

cookie

Web开发中一个很重要的议题就是如何做好用户的整个浏览过程的控制,因为HTTP协议是无状态的,所以用户的每一次请求都是无状态的,我们不知道在整个Web操作过程中哪些连接与该用户有关,我们应该如何来解决这个问题呢?Web里面经典的解决方案是cookie和session,cookie机制是一种客户端机制,把用户数据保存在客户端,而session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构来保存信息,每一个网站访客都会被分配给一个唯一的标志符,即sessionID,它的存放形式无非两种:要么经过url传递,要么保存在客户端的cookies里。当然,你也可以将Session保存到数据库里,这样会更安全,但效率方面会有所下降。

 

一、cookie的介绍

session和cookie是网站浏览中较为常见的两个概念,也是比较难以辨析的两个概念,但它们在浏览需要认证的服务页面以及页面统计中却相当关键。我们先来了解一下cookie怎么来的?考虑这样一个问题:

如何抓取一个访问受限的网页?如新浪微博好友的主页,个人微博页面等。

显然,通过浏览器,我们可以手动输入用户名和密码来访问页面,而所谓的“抓取”,其实就是使用程序来模拟完成

同样的工作,因此我们需要了解“登陆”过程中到底发生了什么。

当用户来到微博登陆页面,输入用户名和密码之后点击“登录”后浏览器将认证信息POST给远端的服务器,服务器执行验证逻辑,如果验证通过,则浏览器会跳转到登录用户的微博首页,在登录成功后,服务器如何验证我们对其他受限制页面的访问呢?因为HTTP协议是无状态的,所以很显然服务器不可能知道我们已经在上一次的HTTP请求中通过了验证。当然,最简单的解决方案就是所有的请求里面都带上用户名和密码,这样虽然可行,但大大加重了服务器的负担(对于每个request都需要到数据库验证),也大大降低了用户体验(每个页面都需要重新输入用户名密码,每个页面都带有登录表单)。既然直接在请求中带上用户名与密码不可行,那么就只有在服务器或客户端保存一些类似的可以代表身份的信息了,所以就有了cookie与session。

cookie,简而言之就是在本地计算机保存一些用户操作的历史信息(当然包括登录信息),并在用户再次访问该站点时浏览器通过HTTP协议将本地cookie内容发送给服务器,从而完成验证,或继续上一步操作。

cookie的原理图:

Cookie是由浏览器维持的,存储在客户端的一小段文本信息,伴随着用户请求和页面在Web服务器和浏览器之间传递。用户每次访问站点时,Web应用程序都可以读取cookie包含的信息。浏览器设置里面有cookie隐私数据选项,打开它,可以看到很多已访问网站的cookies,如下图所示:

 

 

 

cookie是有时间限制的,根据生命期不同分成两种:会话cookie持久cookie

如果不设置过期时间,则表示这个cookie生命周期为从创建到浏览器关闭止,只要关闭浏览器窗口,cookie就消失了。这种生命期为浏览会话期的cookie被称为会话cookie。会话cookie一般不保存在硬盘上而是保存在内存里。

如果设置了过期时间(setMaxAge(606024)),浏览器就会把cookie保存到硬盘上,关闭后再次打开浏览器,这些cookie依然有效直到超过设定的过期时间。存储在硬盘上的cookie可以在不同的浏览器进程间共享,比如两个IE窗口。而对于保存在内存的cookie,不同的浏览器有不同的处理方式。

 

二、Go使用cookie

Go语言中通过net/http包中的SetCookie来设置:

http.SetCookie(w ResponseWriter, cookie *Cookie)

w表示需要写入的response,cookie是一个struct,让我们来看一下cookie对象是怎么样的

type Cookie struct {Name  stringValue stringPath       string    // optionalDomain     string    // optionalExpires    time.Time // optionalRawExpires string    // for reading cookies only// MaxAge=0 means no 'Max-Age' attribute specified.// MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'// MaxAge>0 means Max-Age attribute present and given in secondsMaxAge   intSecure   boolHttpOnly boolRaw      stringUnparsed []string // Raw text of unparsed attribute-value pairs
}

我们来看一个例子,如何设置cookie,以及获取cookie

package mainimport ("net/http""fmt"
)func main() {http.HandleFunc("/setcookie", SetCookie)http.HandleFunc("/getcookie", GetCookie)http.ListenAndServe("localhost:8080", nil)}func SetCookie(w http.ResponseWriter, r *http.Request) {//设置cookiecookie := http.Cookie{Name: "name", Value: "hanru", Path: "/", MaxAge: 60}http.SetCookie(w, &cookie)w.Write([]byte("write cookie ok"))}//Go读取cookie
func GetCookie(w http.ResponseWriter, r *http.Request) {cookie2, _ := r.Cookie("name")fmt.Fprint(w, cookie2)//还有另外一种读取方式//for _, cookie := range r.Cookies() {//  fmt.Fprint(w, cookie.Name)//}
}

运行服务器后,打开浏览器输入地址:http://127.0.0.1:8080/setcookie

运行结果如下:

 

 

 在chrome浏览器中执行:http://127.0.0.1:8080/setcookie, 触发go服务执行设置cookie的动作, 浏览器收到这个信息后, 真正执行设置cookie, 在chrome中可查(chrome://settings/content/cookies目录中的localhost域名中查), 如下:

 

 

可以看到,过期时间是60s, 60s后再次查的时候, 就没有name对应的cookie项了。

接下来,我们获取一下cookie,要在设置cookie的60s内进行获取,否则就取不到了。

然后打开浏览器,输入网址:http://127.0.0.1:8080/getcookie

运行效果如下:

我们等cookie过期消失, 然后再来玩抓包。 好,现在没有name对应的cookie了, 我们连续两次执行:http://127.0.0.1:8080/setcookie, 服务端tcpdump抓包,两次的请求和响应依次如下:

第一次:

第二次:

 

可以看到,第一次请求时, 浏览器发出的请求中不带cookie, 因为浏览器压根就没有这项cookie, 在go服务端的回包中携带了Set-Cookie首部, 浏览器收到这个信息后,将其写入到浏览器本地, 形成cookie。

第二次请求时(因cookie的过期时间设置为了60s, 故必须在60s内发起第二次请求), 此时, 浏览器的http请求中自动携带了cookie信息,go服务端也能收到这个信息。

由此可见, cookie不过是浏览器端的一个环境变量而已, 仅此而已。cookie值存在于浏览器所在的本地电脑中。 而所谓的服务端设置cookie, 其实是服务端给浏览器发送对应的设置cookie信息, 由浏览器来真正执行设置cookie的操作, 存于本地电脑磁盘中。

 

转载自https://www.chaindesk.cn/witbook/17/265,谢谢韩老师

转载于:https://www.cnblogs.com/Paul-watermelon/articles/11030894.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/393196.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PhotoKit 照片库的管理-获取图像

PHAsset部分属性解析 1、HDR 和全景照片 mediaSubtypes 属性验证资源库中的图像在捕捉时是否开启了 HDR&#xff0c;拍摄时是否使用了相机应用的全景模式。 2、收藏和隐藏资源 要验证一个资源是否被用户标记为收藏或被隐藏&#xff0c;只要检查 PHAsset 实例的 favorite 和 hid…

cmail服务器安装后无法登录的解决办法

安装cmailserver 5.4.6软件安装、注册都非常顺利&#xff0c;webmail页面也都正常打开&#xff0c;但是一点“登录”就提示错误&#xff1a; Microsoft VBScript 运行时错误 错误 800a01ad ActiveX 部件不能创建对象: CMailCOM.POP3.1 /mail/login.asp&#xff0c;行 42 点“…

matlab对人工智能,MATLAB与人工智能深度学习和机器学习.PDF

MATLAB与人工智能深度学习和机器学习MATLAB 与人工智能&#xff1a;深度学习有多远&#xff1f;© 2017 The MathWorks, Inc.1机器学习8机器学习无处不在▪ 图像识别 [TBD]▪ 语音识别▪ 股票预测▪ 医疗诊断▪ 数据分析▪ 机器人▪ 更多……9什么是机器学习&#xff1f;机…

leetcode1471. 数组中的 k 个最强值(排序)

给你一个整数数组 arr 和一个整数 k 。 设 m 为数组的中位数&#xff0c;只要满足下述两个前提之一&#xff0c;就可以判定 arr[i] 的值比 arr[j] 的值更强&#xff1a; |arr[i] - m| > |arr[j] - m| |arr[i] - m| |arr[j] - m|&#xff0c;且 arr[i] > arr[j] 请返回…

Spring中WebApplicationInitializer的理解

现在JavaConfig配置方式在逐步取代xml配置方式。而WebApplicationInitializer可以看做是Web.xml的替代&#xff0c;它是一个接口。通过实现WebApplicationInitializer&#xff0c;在其中可以添加servlet&#xff0c;listener等&#xff0c;在加载Web项目的时候会加载这个接口实…

使用fetch封装请求_关于如何使用Fetch API执行HTTP请求的实用ES6指南

使用fetch封装请求In this guide, I’ll show you how to use the Fetch API (ES6) to perform HTTP requests to an REST API with some practical examples you’ll most likely encounter.在本指南中&#xff0c;我将向您展示如何使用Fetch API(ES6 )来执行对REST API的 HTT…

hadoop集群中客户端修改、删除文件失败

这是因为hadoop集群在启动时自动进入安全模式 查看安全模式状态&#xff1a;hadoop fs –safemode get 进入安全模式状态&#xff1a;hadoop fs –safemode enter 退出安全模式状态&#xff1a;hadoop fs –safemode leave转载于:https://www.cnblogs.com/lishengnan/p/a123.ht…

OpenStack nova-network 支持多vlan技术实现片段代码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748

Rest API

什么是接口测试 接口测试又称 API 测试 Application Programming Interface 接口测试是测试系统组件间接口的一种测试。重点关注数据传递。 接口测试一般会用于多系统间交互开发&#xff0c;或者拥有多个子系统的应用系统开发的测试。 为什么要做接口测试 很多系统关联都是基于…

php循环checkbox,php循环删除checkbox | 学步园

一、首先要了解sql语句$SQLdelete from user where id in (1,2,4);表单大概是&#xff1a;form action methodpost input nameID_Dele[] typecheckbox idID_Dele[] value1input nameID_Dele[] typecheckbox idID_Dele[] value2input nameID_Dele[] type首先要了解sql语句$SQL&q…

leetcode1451. 重新排列句子中的单词(排序)

「句子」是一个用空格分隔单词的字符串。给你一个满足下述格式的句子 text : 句子的首字母大写 text 中的每个单词都用单个空格分隔。 请你重新排列 text 中的单词&#xff0c;使所有单词按其长度的升序排列。如果两个单词的长度相同&#xff0c;则保留其在原句子中的相对顺序…

Java+Oracle实现事务——JDBC事务

J2EE支持JDBC事务、JTA事务和容器事务事务&#xff0c;这里说一下怎样实现JDBC事务。 JDBC事务是由Connection对象所控制的&#xff0c;它提供了两种事务模式&#xff1a;自己主动提交和手动提交&#xff0c;默认是自己主动提交。 自己主动提交就是&#xff1a;在JDBC中。在一个…

开源项目贡献者_我如何从一名贡献者转变为一个开源项目维护者

开源项目贡献者by Dhanraj Acharya通过Dhanraj Acharya 我如何从一名贡献者转变为一个开源项目维护者 (How I went from being a contributor to an Open Source project maintainer) I was a lone software developer. When I was in college, I attended the KDE conference…

网络摄像头CVE

CVE-2018-9995 rtsp未授权访问 rtsp后缀整理&#xff1a; Axis&#xff08;安讯士&#xff09; rtsp:// 192.168.200.202/axis-media/media.amp?videocodech264&resolution1280x720 rtsp://IP地址/mpeg4/media.amp rtsp://IP地址/安迅士/AXIS-media/media.amp123D-Link …

Centos中不从skel目录里向其中复制任何文件错误的解决方法

[rootlocalhost www]# useradd -d /webserver/www/ ithovcom useradd&#xff1a;警告&#xff1a;此主目录已经存在。 不从 skel 目录里向其中复制任何文件。 [rootlocalhost www]# ls -a .&http://www.aliyun.com/zixun/aggregation/37954.html">nbsp; .. 发现没…

leetcode91. 解码方法

一条包含字母 A-Z 的消息通过以下方式进行了编码&#xff1a; ‘A’ -> 1 ‘B’ -> 2 … ‘Z’ -> 26 给定一个只包含数字的非空字符串&#xff0c;请计算解码方法的总数。 示例 1: 输入: “12” 输出: 2 解释: 它可以解码为 “AB”&#xff08;1 2&#xff09;或者…

php 系统平均负载,Linux_解析Linux系统的平均负载概念,一、什么是系统平均负载(Load a - phpStudy...

解析Linux系统的平均负载概念一、什么是系统平均负载(Load average)&#xff1f;在Linux系统中&#xff0c;uptime、w、top等命令都会有系统平均负载load average的输出&#xff0c;那么什么是系统平均负载呢&#xff1f;系统平均负载被定义为在特定时间间隔内运行队列中的平均…

Elastic-job使用及原理

一、原理 elastic-job有lite版和cloud版&#xff0c;最大的区别是有无调度中心&#xff0c;笔者采用的是lite版本&#xff0c;无中心化。 tips: 第一台服务器上线触发主服务器选举。主服务器一旦下线&#xff0c;则重新触发选举&#xff0c;选举过程中阻塞&#xff0c;只有主服…

构建持续交付_如何使交付成为您的重点将如何帮助您构建高质量的应用程序

构建持续交付by Simon Schwartz西蒙施瓦茨(Simon Schwartz) 如何使交付成为您的重点将如何帮助您构建高质量的应用程序 (How making delivery your focus will help you build quality applications) I was recently asked by our company’s executive team why our team was…

微信退款通知,退款回调数据解密.SHA256签名AEAD_AES_256_GCM解密

$xmlResult file_get_contents("php://input");//获取微信的数据$result $this->xmlToArray($xmlResult);//将xml转成数组 // 将加密的数据解密,方法在下面$reqInfo $this->refund_decrypt($result[req_info]); /** 退款通知解密* Author WangZhaoBo* param…