一、背景
访问4年前在Go playground上分享的代码片段,都提示Unavailable For Legal Reasons,请求状态码为451。由于内容比较重要,花了一些时间研究原因,最终除了一个特例,其他都找回来。
二、关于HTTP 451
HTTP 451 Unavailable For Legal Reasons, 即因法律原因不可用。当用户请求访问某个经政府审核等查核方法后认定不合法的来源时,就会显示这个错误代码。
详细说明请查阅维基百科HTTP 451
三、具体错误分析
1、错误详情
访问https://play.golang.org/p/wxapmDYT6w,提示错误如下:
Unavailable For Legal Reasons
Viewing and/or sharing code snippets is not available in your country for legal reasons. This message might also appear if your country is misdetected. If you believe this is an error, please file an issue.
2、错误原因
查了下在Go playground的github仓库中有好几个相关的issue(23038、20866), 并且都已经close了。
原因是对某些地区做了访问限制,通过HTTP Header中的X-Appengine-Country来过滤, 我们来看看源码
抛出错误的地方edit.go
... if strings.HasPrefix(r.URL.Path, "/p/") { if !allowShare(r) { w.WriteHeader(http.StatusUnavailableForLegalReasons) w.Write([]byte(`<h1>Unavailable For Legal Reasons</h1><p>Viewing and/or sharing code snippets is not available in your country for legal reasons. This message might also appear if your country is misdetected. If you believe this is an error, please <a href="https://golang.org/issue">file an issue</a>.</p>`)) return } ... }
限制的地方share.go
func allowShare(r *http.Request) bool { if os.Getenv("GAE_INSTANCE") == "" { return true } switch r.Header.Get("X-AppEngine-Country") { case "", "ZZ", "CN": return false } return true }
3、官方问题修复
官方的bugfix修复说明是loosen restrictions on IPs permitted to share(放宽对允许共享的IP的限制),我理解是某些共享IP解析到的X-AppEngine-Country为ZZ(unknown country), 取消了ZZ和””, 仅仅限制CN,【what? 为啥要单独限制CN啊】
bugfix后,diff可见这里
func allowShare(r *http.Request) bool { if r.Header.Get("X-AppEngine-Country") == "CN" { return false } return true }
4、本地问题解决
看了官方的修复说明,构造了X-AppEngine-Country为US的Header发起请求,还是有类似错误。
本地测试确实可以接受到X-AppEngine-Country的值
package main import ( "fmt" "net/http" ) func HelloHandler(w http.ResponseWriter, r *http.Request) { country := r.Header.Get("X-AppEngine-Country") fmt.Println(country) // fmt.Fprintf(w, "Hello World") } func main () { http.HandleFunc("/", HelloHandler) http.ListenAndServe(":8000", nil) }
把pac的网络代理换成VPN后就可以访问了,并且设置X-AppEngine-Country为CN依旧可以访问,具体原因有待进一步研究。
四、小结
1、重要的资料,及时整理备份
2、Go playground内容不确定是否是永久保存,目前看4年前的内容还可以访问,也有偶尔丢失的情况,从DB中没查到,提示在edit.go中
https://play.golang.org/p/L-Uzdmnln提示Snippet not found