现象描述
cookie字段中以分号开头,在go获取cookie的时候,就获取不到这个字段,举例待获取的cookie字段是token=abc
,但是cookie中写入的是;token=abc
,此时在go1.13版本以上就无法正确获得到token这个值。
分析代码
/usr/local/go/src/net/http/cookie.go
这个文件中的 readCookies
方法,最关键的就是if splitIndex := strings.Index(line, ";"); splitIndex > 0 {
这行
1.13版本
// readCookies parses all "Cookie" values from the header h and
// returns the successfully parsed Cookies.
//
// if filter isn't empty, only cookies of that name are returned
func readCookies(h Header, filter string) []*Cookie {
lines := h["Cookie"]
if len(lines) == 0 {
return []*Cookie{}
}
cookies := make([]*Cookie, 0, len(lines)+strings.Count(lines[0], ";"))
for _, line := range lines {
line = textproto.TrimString(line)
var part string
for len(line) > 0 { // continue since we have rest
if splitIndex := strings.Index(line, ";"); splitIndex > 0 {// 这行是关键
part, line = line[:splitIndex], line[splitIndex+1:]
} else {
part, line = line, ""
}
part = textproto.TrimString(part)
if len(part) == 0 {
continue
}
name, val := part, ""
if j := strings.Index(part, "="); j >= 0 {
name, val = name[:j], name[j+1:]
}
if !isCookieNameValid(name) {
continue
}
if filter != "" && filter != name {
continue
}
val, ok := parseCookieValue(val, true)
if !ok {
continue
}
cookies = append(cookies, &Cookie{Name: name, Value: val})
}
}
return cookies
}
1.12版本
// readCookies parses all "Cookie" values from the header h and
// returns the successfully parsed Cookies.
//
// if filter isn't empty, only cookies of that name are returned
func readCookies(h Header, filter string) []*Cookie {
lines, ok := h["Cookie"]
if !ok {
return []*Cookie{}
}
cookies := []*Cookie{}
for _, line := range lines {
parts := strings.Split(strings.TrimSpace(line), ";") // 这行是关键
if len(parts) == 1 && parts[0] == "" {
continue
}
// Per-line attributes
for i := 0; i < len(parts); i++ {
parts[i] = strings.TrimSpace(parts[i])
if len(parts[i]) == 0 {
continue
}
name, val := parts[i], ""
if j := strings.Index(name, "="); j >= 0 {
name, val = name[:j], name[j+1:]
}
if !isCookieNameValid(name) {
continue
}
if filter != "" && filter != name {
continue
}
val, ok := parseCookieValue(val, true)
if !ok {
continue
}
cookies = append(cookies, &Cookie{Name: name, Value: val})
}
}
return cookies
}
原因分析
在1.12版本的时候,是通过分号来分割来获取字段的,而1.13版本中是判断分号所在位置,而恰巧;token
是分号的位置是0
就会走到他的else
分支,造成无法正确获得字段。
虽然这是一个写cookie不够标准造成的问题,但是如果写cookie方无法修改的时候,我们只能自己想办法。
解决办法
那么如果后端来解决这个问题,我的方式是,通过中间件加工request.header
,重写cookie,以gin框架为例
代码如下
func(c *gin.Context) {
if len(c.Request.Header["Cookie"]) > 0 {
for _, ccv := range c.Request.Header["Cookie"] {
ccv = textproto.TrimString(ccv)
if fIndex := strings.Index(ccv, ";"); fIndex == 0 {
c.Request.Header["Cookie"] = append(c.Request.Header["Cookie"], ccv[fIndex+1:])
}
}
}
}
这样cookie中就有一份token=abc
的数据了,在后续的循环中可以正常获得。
网友评论