在Go语言的Web开发场景中,HTTP Cookie常用于用户身份识别、会话状态保持等功能,正确检索和处理Cookie是保证相关业务逻辑正常运行的基础。Go的标准库net/http提供了完善的Cookie操作支持,开发者可以直接使用相关接口完成Cookie的读写与解析工作。
从HTTP请求中检索Cookie
当客户端发送请求到服务端时,Cookie会携带在请求头的Cookie字段中,我们可以通过http.Request结构体提供的方法获取Cookie信息。
获取单个指定名称的Cookie
使用Request.Cookie(name string)方法可以获取指定名称的Cookie,该方法返回*http.Cookie和error,如果不存在对应名称的Cookie,会返回http.ErrNoCookie错误。
package main
import (
"fmt"
"net/http"
)
func cookieHandler(w http.ResponseWriter, r *http.Request) {
// 获取名称为user_token的Cookie
cookie, err := r.Cookie("user_token")
if err != nil {
if err == http.ErrNoCookie {
fmt.Fprintf(w, "未找到user_token Cookie")
return
}
fmt.Fprintf(w, "获取Cookie出错: %v", err)
return
}
// 输出Cookie的值
fmt.Fprintf(w, "Cookie值: %s", cookie.Value)
}
func main() {
http.HandleFunc("/get-cookie", cookieHandler)
http.ListenAndServe(":8080", nil)
}
获取请求中的所有Cookie
如果需要获取请求携带的所有Cookie,可以使用Request.Cookies()方法,该方法返回[]*http.Cookie切片,包含请求中的所有Cookie对象。
func allCookieHandler(w http.ResponseWriter, r *http.Request) {
cookies := r.Cookies()
if len(cookies) == 0 {
fmt.Fprintf(w, "请求中无Cookie")
return
}
for _, c := range cookies {
fmt.Fprintf(w, "Cookie名称: %s, 值: %sn", c.Name, c.Value)
}
}
Cookie属性的解析与处理
获取到http.Cookie对象后,可以访问其各个属性字段,获取Cookie的附加信息,常见的属性包括:
- Name:Cookie的名称
- Value:Cookie的值
- Path:Cookie的作用路径,默认是设置该Cookie的路径
- Domain:Cookie的作用域名
- Expires:Cookie的过期时间,零值表示会话Cookie
- MaxAge:Cookie的最大存活时间,单位为秒,优先于Expires
- Secure:是否仅通过HTTPS传输
- HttpOnly:是否禁止客户端脚本访问
示例:解析Cookie的过期时间和安全属性
func parseCookieHandler(w http.ResponseWriter, r *http.Request) {
cookie, err := r.Cookie("session_id")
if err != nil {
fmt.Fprintf(w, "未找到session_id Cookie")
return
}
fmt.Fprintf(w, "Cookie名称: %sn", cookie.Name)
fmt.Fprintf(w, "Cookie值: %sn", cookie.Value)
fmt.Fprintf(w, "过期时间: %vn", cookie.Expires)
fmt.Fprintf(w, "最大存活时间: %d秒n", cookie.MaxAge)
fmt.Fprintf(w, "是否仅HTTPS传输: %vn", cookie.Secure)
fmt.Fprintf(w, "是否禁止脚本访问: %vn", cookie.HttpOnly)
}
设置HTTP响应的Cookie
服务端可以通过http.ResponseWriter的Header().Add()方法或者http.SetCookie函数设置响应Cookie,推荐使用标准库提供的http.SetCookie函数,它会自动处理Cookie的编码和格式拼接。
package main
import (
"fmt"
"net/http"
"time"
)
func setCookieHandler(w http.ResponseWriter, r *http.Request) {
// 创建一个Cookie对象
cookie := &http.Cookie{
Name: "user_token",
Value: "abc123xyz",
Path: "/",
Domain: "ipipp.com",
Expires: time.Now().Add(24 * time.Hour),
MaxAge: 86400,
Secure: true,
HttpOnly: true,
SameSite: http.SameSiteLaxMode,
}
// 将Cookie写入响应头
http.SetCookie(w, cookie)
fmt.Fprintf(w, "Cookie设置成功")
}
func main() {
http.HandleFunc("/set-cookie", setCookieHandler)
http.ListenAndServe(":8080", nil)
}
Cookie处理的常见注意事项
同名Cookie的处理
同一个请求中可能携带多个同名的Cookie,比如不同路径下设置了相同名称的Cookie,此时r.Cookie(name)方法会返回第一个匹配到的Cookie,如果需要获取所有同名的Cookie,需要遍历r.Cookies()切片进行筛选。
Cookie值的编码
Cookie的值如果包含特殊字符,比如空格、中文、等号等,需要进行编码处理,Go的net/url包提供了QueryEscape和QueryUnescape方法可以完成编码和解码工作。
import "net/url"
func setEncodedCookie(w http.ResponseWriter, r *http.Request) {
// 对Cookie值进行编码
rawValue := "用户令牌 123"
encodedValue := url.QueryEscape(rawValue)
cookie := &http.Cookie{
Name: "encoded_token",
Value: encodedValue,
Path: "/",
}
http.SetCookie(w, cookie)
fmt.Fprintf(w, "编码后的Cookie已设置")
}
func getEncodedCookie(w http.ResponseWriter, r *http.Request) {
cookie, err := r.Cookie("encoded_token")
if err != nil {
fmt.Fprintf(w, "未找到Cookie")
return
}
// 对Cookie值进行解码
decodedValue, err := url.QueryUnescape(cookie.Value)
if err != nil {
fmt.Fprintf(w, "解码失败: %v", err)
return
}
fmt.Fprintf(w, "解码后的Cookie值: %s", decodedValue)
}
安全属性配置
对于涉及用户身份的Cookie,建议开启HttpOnly属性,避免被客户端JavaScript脚本窃取;如果网站使用HTTPS协议,建议开启Secure属性,保证Cookie仅通过加密通道传输;同时可以根据需求配置SameSite属性,防范跨站请求伪造攻击。