Go Web:Cookie
Cookie用来解决http协议无状态的问题。
首先,在服务端生成Cookie,然后在http响应header中设置Set-Cookie字段,客户端会读取到Set-Cookie字段后,会将cookie信息存储起来,下次继续访问服务端时,会在http请求中设置Cookie字段并发送给服务端,服务端可以解析这个Cookie字段,从而知道这个客户端之前已经和自己有过会话(上下文),然后再执行相应的逻辑代码。
Cookie分为两种类型:session cookie和persistent cookie。
- Session Cookie也称为临时Cookie,客户端只会将cookie数据存储在http client进程的内容中,不会保存到磁盘文件中(或其它存储设备),浏览器关闭(或者说http client进程退出)的时候,cookie就删除了。
- persistent cookie是持久化cookie,浏览器退出也不删除,而是根据服务端发送cookie时设置的过期时长判断cookie是否过期,只要cookie还有效,客户端就会携带cookie访问服务端。
Cookie struct
$ go doc http.cookie
type Cookie struct {
Name string
Value string
Path string // optional
Domain string // optional
Expires time.Time // optional
RawExpires 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 seconds
MaxAge int
Secure bool
HttpOnly bool
Raw string
Unparsed []string // Raw text of unparsed attribute-value pairs
}
func (c *Cookie) String() string
一个Cookie代表一个http cookie。服务端可以设置多个Set-Cookie字段发送给客户端。。
Name和Value分别设置这个cookie的key/value。一定要有至少一个能唯一区分客户端的ID类的value。
Expires指定cookie到什么时候过期,是一个时间值。当指定为过去的时间值时,表示这个cookie已经过期。
MaxAge也用来设置cookie什么时候过期,MaxAge为负数或等于0表示立即过期,MaxAge大于0表示过多少秒之后过期。
MaxAge和Expires都可以设置cookie持久化时的过期时长,Expires是老式的过期方法,如果可以,应该使用MaxAge设置过期时间,但有些老版本的浏览器不支持MaxAge。如果要支持所有浏览器,要么使用Expires,要么同时使用MaxAge和Expires。
Path和Domain设置访问哪些路径或域名范围的主机时应该携带这个cookie。如果不设置,则访问所有路径、该Domain下的主机都携带cookie。
cookie.Path("/WEB16");
代表访问WEB16应用中的任何资源都携带cookie
cookie.Path("/WEB16/cookietest");
代表访问WEB16中的cookietest时才携带cookie信息
cookie.Domain(".foo.com");
这对foo.com域下的所有主机都生效(如www.foo.com),但不包括子域www.abc.foo.com
Secure和HttpOnly字段为cookie提供一些保护机制。这两个cookie属性的介绍,参见:
Cookie有一个String()方法,用来将Cookie实例转换成字符串。转化成字符串之后就可以直接设置在Header中。
例如,下面是登录youtube的时候,对方发送给我的cookie:
设置Cookie并发送给客户端
package main
import (
"fmt"
"net/http"
)
func setCookie(w http.ResponseWriter, r *http.Request) {
// 定义两个cookie
c1 := http.Cookie{
Name: "first_cookie",
Value: "Go Programming",
}
c2 := http.Cookie{
Name: "second_cookie",
Value: "Go Web Programming",
HttpOnly: true,
}
// 设置Set-Cookie字段
w.Header().Set("Set-Cookie", c1.String())
w.Header().Add("Set-Cookie", c2.String())
fmt.Fprintf(w, "%s\n%s\n", c1.String(), c2.String())
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/set_cookie", setCookie)
server.ListenAndServe()
}
访问http://127.0.0.1:8080/set_cookie
时,查看Header将显式Set-Cookie字段。
$ curl -i http://127.0.0.1:8080/set_cookie
HTTP/1.1 200 OK
Set-Cookie: first_cookie="Go Programming"
Set-Cookie: second_cookie="Go Web Programming"; HttpOnly
Date: Tue, 27 Nov 2018 10:12:44 GMT
Content-Length: 75
Content-Type: text/plain; charset=utf-8
first_cookie="Go Programming"
second_cookie="Go Web Programming"; HttpOnly
http包提供了一个SetCookie()函数,可以直接用来设置Set-Cookie字段。
func SetCookie(w ResponseWriter, cookie *Cookie)
注意,第二个字段是指针类型的Cookie。
修改前面的示例,使用SetCookie()函数发送Set-Cookie字段:
func setCookie(w http.ResponseWriter, r *http.Request) {
c1 := http.Cookie{
Name: "first_cookie",
Value: "Go Programming",
}
c2 := http.Cookie{
Name: "second_cookie",
Value: "Go Web Programming",
HttpOnly: true,
}
http.SetCookie(w, &c1)
http.SetCookie(w, &c2)
}
取得客户端携带的cookie
由于客户端发起请求时,如果携带cookie,是直接放在Request的Cookie Header中的。所以,可以通过Request取得客户端携带的cookie信息。当然,也可以通过Request的方法Cookie()或Cookies()取得cookie信息。
func (r *Request) Cookie(name string) (*Cookie, error)
func (r *Request) Cookies() []*Cookie
- Cookie(Name)只取某个cookie
- Cookies()取所有的cookie
下面是通过Request Header的方式取Cookie的示例:
package main
import (
"fmt"
"net/http"
)
func setCookie(w http.ResponseWriter, r *http.Request) {
c1 := http.Cookie{
Name: "first_cookie",
Value: "Go Programming",
}
c2 := http.Cookie{
Name: "second_cookie",
Value: "Go Web Programming",
HttpOnly: true,
}
http.SetCookie(w, &c1)
http.SetCookie(w, &c2)
}
func getCookie(w http.ResponseWriter, r *http.Request) {
cookie := r.Header.Get("Cookie")
fmt.Fprintf(w, "%s\n", cookie)
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/set_cookie", setCookie)
http.HandleFunc("/get_cookie", getCookie)
server.ListenAndServe()
}
在访问http://127.0.0.1:8080/set_cookie
之后不要关闭浏览器,再次访问http://127.0.0.1:8080/get_cookie
,将输出:
first_cookie="Go Programming"; second_cookie="Go Web Programming"
或者,使用curl记录cookie,并下次访问时读取cookie:
$ curl -c a.cookie http://127.0.0.1:8080/set_cookie
$ curl -b a.cookie http://127.0.0.1:8080/get_cookie
first_cookie="Go Programming"; second_cookie="Go Web Programming"
下面是改用Request的Cookie()和Cookies()方法取cookie:
func getCookie(w http.ResponseWriter, r *http.Request) {
cookie, err := r.Cookie("first_cookie")
if err != nil {
fmt.Fprintf(w, "Cat't get Cookie")
}
cookies := r.Cookies()
fmt.Fprintf(w, "%s\n%s\n", cookie, cookies)
}
访问结果:
$ curl -c a.cookie http://127.0.0.1:8080/set_cookie
$ curl -b a.cookie http://127.0.0.1:8080/get_cookie
first_cookie="Go Programming"
[first_cookie="Go Programming" second_cookie="Go Web Programming"]
设置cookie过期示例:发送临时消息
有时候可能想要让客户端的某些操作只显示一次相关消息,例如post一篇帖子失败后,应该显示失败信息,但下次再访问不应该再显示这些失败信息。
通过设置cookie过期的技巧,可以实现一些一次性操作。设置cookie过期的方式是设置MaxAge为负数或0,为了兼容所有浏览器,可以设置Expires为过去的一段时间。
下面的示例中,将一段数据使用URL格式编码后作为flash cookie的值。当客户端访问set_message的时候,就会在http Client进程中保存这段cookie。再访问show_message的时候,handler解析客户端携带的cookie,并设置一个Set-Cookie字段,这个字段的作用是使之前保存的cookie过期。然后输出解码后客户端携带的cookie的值。再次刷新show_message,将得到不同的输出结果。
package main
import (
"encoding/base64"
"fmt"
"net/http"
"time"
)
func set_message(w http.ResponseWriter, r *http.Request) {
msg := []byte("Hello World")
cookie := http.Cookie{
Name: "flash",
Value: base64.URLEncoding.EncodeToString(msg),
}
http.SetCookie(w, &cookie)
}
func show_message(w http.ResponseWriter, r *http.Request) {
cookie, err := r.Cookie("flash")
if err != nil {
if err == http.ErrNoCookie {
fmt.Fprintln(w, "no messages to show")
}
} else {
expire_cookie := http.Cookie{
Name: "flash",
MaxAge: -1,
Expires: time.Unix(1, 0),
}
http.SetCookie(w, &expire_cookie)
value, _ := base64.URLEncoding.DecodeString(cookie.Value)
fmt.Fprintln(w, string(value))
}
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/set_message", set_message)
http.HandleFunc("/show_message", show_message)
server.ListenAndServe()
}
使用curl测试。注意,首先访问set_message的时候,保存cookie到b.cookie文件。再访问show_message的时候,也要带上-c b.cookie
将已保存的cookie设置为过期,之后再访问show_message就会出现预期的结果:
$ curl -c b.cookie http://127.0.0.1:8080/set_message
$ curl -b b.cookie -c b.cookie http://127.0.0.1:8080/show_message
Hello World
$ curl -b b.cookie -c b.cookie http://127.0.0.1:8080/show_message
no messages to show
Go Web:Cookie的更多相关文章
- 信息安全-技术-Web:cookie
ylbtech-信息安全-技术-Web:cookie Cookie,有时也用其复数形式 Cookies,指某些网站为了辨别用户身份.进行 session 跟踪而储存在用户本地终端上的数据(通常经过加密 ...
- 数据存储的两种方式:Cookie 和Web Storage
数据存储的两种方式:Cookie 和Web Storage 1.Cookie Cookie的作用就像你去超市购物时,第一次给你办张购物卡,这个购物卡里存放了一些你的个人信息,下次你再来这个连锁超市时, ...
- 数据存储的两种方式:Cookie 和Web Storage(转)
数据存储的两种方式:Cookie 和Web Storage 数据存储的两种方式:Cookie 和Web Storage 1.Cookie Cookie的作用就像你去超市购物时,第一次给你办张购物卡 ...
- java的会话管理:Cookie和Session
java的会话管理:Cookie和Session 1.什么是会话 此处的是指客户端(浏览器)和服务端之间的数据传输.例如用户登录,购物车等 会话管理就是管理浏览器客户端和服务端之间会话过程产生的会话数 ...
- JavaWeb学习之转发和重定向、会话技术:cookie、session、验证码实例、URLConnection使用(下载网页)(4)
1.转发和重定向 HttpServletResponse response 转发: RequestDispatcher dispatcher = request.getRequestDispatche ...
- 关于session的实现:cookie与url重写
本文讨论的语境是java EE servlet. 我们都知道session的实现主要两种方式:cookie与url重写,而cookie是首选(默认)的方式,因为各种现代浏览器都默认开通cookie功能 ...
- 客户端技术:Cookie 服务端技术:HttpSession
客户端技术:Cookie 服务端技术:HttpSession 07. 五 / android基础 / 没有评论 一.会话技术1.什么是会话:客户打开浏览器访问一个网站,访问完毕之后,关闭浏览器.这 ...
- JavaEE:Cookie和Session
Cookie是客户端技术,程序把每个用户的数据以cookie的形式写给用户各自的浏览器.当用户使用浏览器再去访问服务器中的web资源时,就会带着各自的数据去.这样web资源处理的就是用户各自的数据了. ...
- javaWeb学习总结(7)-关于session的实现:cookie与url重写
本文讨论的语境是java EE servlet.我们都知道session的实现主要两种方式:cookie与url重写,而cookie是首选(默认)的方式,因为各种现代浏览器都默认开通cookie功能, ...
随机推荐
- 【慕课网实战】三、以慕课网日志分析为例 进入大数据 Spark SQL 的世界
前置要求: 1)Building Spark using Maven requires Maven 3.3.9 or newer and Java 7+ 2)export MAVEN_OPTS=&qu ...
- nice coding (与其亡羊补牢,不如未雨绸缪)
一.需求前 架构规范 建模规范 编码规范(流程控制,方法抽取,日志打印等) <Effective Java> <Design Patterns> 二.需求中 1. 明确需求(别 ...
- WSGI协议以及对服务器的影响
下面的内容纯属个人学习心得,如果对于我的观点有疑问,敬请留言,我将虚心向大牛学习. WSGI的全称是WEB SERVICE GATEWAY INTERFACE.WSGI 不是服务器,不是API,也不是 ...
- Maven 在新版eclipse报错的解决
转自Stack Overflow Remove all your failed downloads: Linux: find ~/.m2 -name "*.lastUpdated" ...
- Python之旅Day9 进程&线程
进程 线程 多进程 多线程
- Android-MySQLiteOpenHelper的理解
MySQLiteOpenHelper: package com.esandinfo; import android.content.Context; import android.database.s ...
- 使用 VSTS 进行 CI 的过程中,无法识别 .NET Core 2.x 的情况处理
大概是由于 .NET Core 2.1 还没有正式发布,使用 VSTS 进行持续集成(CI)的过程中,自动 Build 的环节无法识别 .NET Core 2.1 的框架,查看日志会提示如下错误: V ...
- 【SP26073】DIVCNT1 - Counting Divisors 题解
题目描述 定义 \(d(n)\) 为 \(n\) 的正因数的个数,比如 \(d(2) = 2, d(6) = 4\). 令 $ S_1(n) = \sum_{i=1}^n d(i) $ 给定 \(n\ ...
- 阿里巴巴Java开发规约及插件安装
[上海尚学堂编辑整理]10.14日,阿里巴巴在杭州云栖大会上,正式发布了由阿里巴巴 P3C 项目组,经过 近一年的持续研发,正式发布众所期待的 <阿里巴巴 Java 开发规约>的扫描插件. ...
- JVM内存分配和垃圾收集策略
java内存区域 程序计数器 因为java可以多线程并发执行,因此,为了线程切换后能恢复到正确的执行位置,每个线程都需要一个独立的程序计数器.记录正在执行的虚拟机字节码指令的地址. 这个区域不会产生内 ...