go语言在不支持cgo的情况下访问https链接

最近一些新项目都直接用go,还是比Java爽很多的。很对内部服务都只针Java设计的问题,这些坑要么自己填完了,要么有人替我用php填完了……现在大概有两个项目是用go写的,一个是有道词典的易信公众帐号的那个答题小游戏(易信里关注“有道词典”之后回复“@答题”,各种英语题百科题……)的后台,另一个暂时先不说了……

昨天开发小游戏新功能的时候遇到了因服务器gcc版本过低导致无法访问https的问题,在这里记下解决过程。

易信公众帐号的API是强制https访问的,所以需要调用一些接口时我直接用http包的Get函数来访问,在本机测试没问题之后在MAC下跨平台编译linux/amd64版本放到服务器运行发现Get会报error,内容是:

x509: failed to load system roots and no roots provided

搜了下发现x509跟证书验证之类的有关,应该能定位出问题出在用了https上。因为本机测试完全没问题,所以肯定不是Get不支持https,上网搜了下那句报错,go-nuts里的解答大概是说跟cgo有关,其他地方发现大多数出这个错误是因为go get一个库然后里面下载了https下的代码(大都是google code上)。解决方案就是开CGO。但因为我是交叉编译,而交叉编译是不支持cgo的,所以意味着不能交叉编译。因此要么在服务器编译要么用一个64位linux编译。第一个方案不靠谱,因为服务器如果还得现编译的话运维那边操作会复杂,之前解压一个包nohup运行run.sh的无压力部署就完全不能用了而且需要服务器专门为了我这个小项目装go就更麻烦了;第二个方案试了下发现还是报错,查了下发现是因为服务器gcc版本太低才3.6,至少需要4.x才可以,为了这个项目给各个服务器升级gcc也不现实。

继续搜,这时候发现go-nuts有个帖子的回复里提到可以把certificate chain写死到代码里,代码地址在 https://gist.github.com/laher/5795578 ,里面的例子是拿github的证书链分别访问github和facebook的https地址,前者可以后者报错。下载下来在无cgo的服务器运行了下能正确访问github,于是就可以用这种方案绕过cgo了。

openssl s_client -connect api.yixin.im:443 -showcerts > file.txt

随便找个有openssl的机器用上面的命令可以获得易信api域名的证书链,要是想获得其他域名对应改一下就可以,file.txt里删掉没用的只留类似gist里“—–BEGIN CERTIFICATE—–”、“—–END CERTIFICATE—–”之间的部分,一般域名的证书链大概是两个或者三个证书。

因为http.Client是并发安全的,所以只需要在init里初始化一个针对特定域名的全局的client,就能随时用随时client.Get/Post等等。

系统自带的库里除了http之外还有一些也会用到cgo,交叉编译或目标机器不支持cgo都会导致失效,好像比较常见的还有DNS之类的问题,反正我暂时是不会遇到了……除了这种小坑之外,go的跨平台交叉编译还是非常方便的。

 

 

继续广告:搞了个微信公众号,账号yangzhetest,用来同步发我的博客文章。如果觉得RSS不方便,可以用微信看。顺便说一句,那天看微博发现确实很多人跟我一样因为GR关了rss就不怎么用了。关闭Reader时,Google说RSS落伍了,如果因为自己关闭Reader然后用Rss的人真的减少了,也不知道该说他这是成功的“预言”,还是创造了历史。

image


已发布

分类

来自

标签:

评论

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注