## 起因
最近的项目从golang0.9升级到golang1.13后,项目中出现了很特殊的现象,在APP里,用户登录后访问页面正常,用户不登录,报错。
## 处理过程
1. Charles抓包发现,登录的情况下,服务返回的是protobuf的数据,未登录情况下返回的是json结构。服务是根据cookie中传入的数据来返回对应的数据类型。初步断定未登录情况下无法获取到cookie
2. 检查登录和未登录情况下cookie的区别。
- 登录:**serviceToken=abc**;type=protobuf;session=123
- 未登录:;type=protobuf;session=123
serviceToken是登录后的验证信息,用户如果未登录,数据不存在,但是分号却存在。初步怀疑是golang版本引起
3. 在代码不变的情况下,使用不同golang版本生成服务,使用脚本进行测试
```php
<?php
$url = "http://10.220.130.8:8081/in/app/sync";
//$url = "http://in-go.buy.mi.com/in/app/sync";
$cookie = "; xmuuid=XMGUEST-FCF117BF-4D1B-272F-829D-25E19826D4F8;type=protobuf";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_COOKIE, $cookie);
$output = curl_exec($ch);
curl_close($ch);
var_dump($output,11) ;
```
确定是golang版本问题
4. 查看源码,在net/http/cookie.go中,可以看到
- golang1.12将cookie直接做了分割strings.Split(strings.TrimSpace(line), ";"),所以无论分号在什么位置都能解析出来
- 在golang1.13中 if splitIndex := strings.Index(line, ";"); splitIndex > 0 ,使用这种切割方式,如果引号位于第一个,整个获取过程便结束了,无法获得正确的cookie值
golang1.12
```go
// 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
}
```
golang1.13
```go
// 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 = strings.TrimSpace(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 = strings.TrimSpace(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. 胆大心细
- 升级这种操作有时候是必然要做的,新版会有更多的新特性,带来更好的性能,情况合适的话,需要大胆去做
- 一定要让测试同学,将各个终端,各种状态,各种流程过一遍
- 上线之后,需要继续观察
2. 遇到问题,需要不断追查,这是一个自我成长和提升的过程
3. 小的方面也需要完美,否则会导致很大的代价。客户端写cookie的方法虽然没错,但也不是很标准,当时写的时候也没在意。目前老的版本已经无法修复,如果想升级1.13,要么修复golang里的问题,要么在项目里添加处理cookie的逻辑,处理起来都有些麻烦
## 最后
大家如果喜欢我的文章,可以关注我的公众号(程序员麻辣烫)
![](https://user-gold-cdn.xitu.io/2020/6/6/1728870aaad58afd?w=258&h=258&f=jpeg&s=28085)
**往期文章回顾:**
1. [Redis实现分布式锁](https://mp.weixin.qq.com/s/3i0fVLgAYc_QkvBvTW2JCQ)
2. [Golang源码BUG追查](https://mp.weixin.qq.com/s/pfV1guaUwUlkiZx6xdXzxg)
3. [事务原子性、一致性、持久性的实现原理](https://mp.weixin.qq.com/s/yQM9vzhFxgCrzkx3EjfIPQ)
4. [如何锻炼自己的记忆力](https://mp.weixin.qq.com/s/q05zTz49--tJmnYCboLOQw)
5. [CDN请求过程详解](https://mp.weixin.qq.com/s/HFfs0sJjY8cwpDYaIa5ZjQ)
6. [关于程序员职业发展的思考](https://mp.weixin.qq.com/s/QR2_3j1rbfiXoZGlSqpSRw)
7. [记博客服务被压垮的历程](https://mp.weixin.qq.com/s/Y6Axp4wfa3uSMAXS2GKwnA)
8. [常用缓存技巧](https://mp.weixin.qq.com/s/xElsNUjxiT0MYZuVJct6Gw)
9. [如何高效对接第三方支付](https://mp.weixin.qq.com/s/NM34aevx3DBT1czcoFMJWw)
10. [Gin框架简洁版](https://mp.weixin.qq.com/s/X9pyPZU63j5FF4SDT4sHew)
11. [关于代码review的思考](https://mp.weixin.qq.com/s/M0ExjoIGHVA6bI9g8ZLAog)
12. [InnoDB锁与事务简析](https://mp.weixin.qq.com/s/K8s_1cYRK5mkY_b4_XOeng)
13. [Markdown编辑器推荐-typora](https://mp.weixin.qq.com/s/TeYMjeJOmKm2cbZychLcOw)
有疑问加站长微信联系(非本文作者))