如何判断请求协议?HTTP转HTTPS重定向遇r.TLS等字段为空问题
解决Go服务在Cloud Foundry上无法区分HTTP/HTTPS请求的问题
我明白你遇到的困扰了——在Cloud Foundry(CF)上运行Go服务时,不管用户用HTTP还是HTTPS访问,r.URL.Scheme和r.TLS始终是nil,导致你没法正确判断请求协议来完成HTTPS重定向。这其实是CF的运行机制导致的:
CF的gorouter(路由组件)会提前终止TLS连接,然后用普通的HTTP请求把流量转发给你的应用实例。所以你的应用收到的所有请求都是HTTP协议的,自然r.TLS会是nil,r.URL.Scheme也不会自动设置为HTTPS。
正确的判断方法:检查X-Forwarded-Proto请求头
CF的gorouter会自动为转发的请求添加X-Forwarded-Proto请求头,这个头的值就是用户实际发起请求时用的协议(http或https)。你可以通过这个头来判断请求的原始协议,进而完成重定向逻辑。
修改你的redirectTLS中间件
把原来依赖r.TLS的判断逻辑换成检查X-Forwarded-Proto头,调整后的代码如下:
func redirectTLS(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // 获取用户实际发起请求的协议 originalProto := r.Header.Get("X-Forwarded-Proto") // 如果原始协议不是HTTPS,就重定向到HTTPS地址 if originalProto != "https" { log.Info("Redirecting to HTTPS") targetURL := fmt.Sprintf("https://%s%s", r.Host, r.RequestURI) http.Redirect(w, r, targetURL, http.StatusMovedPermanently) return } log.Info("Not Redirecting to HTTPS") next.ServeHTTP(w, r) }) }
额外优化:兼容多环境运行
如果你的服务需要在本地或其他非CF环境运行,可以给中间件加个环境判断,兼顾不同场景的协议检测逻辑:
func redirectTLS(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var isHTTPS bool if cfenv.IsRunningOnCF() { // CF环境下用X-Forwarded-Proto判断原始协议 isHTTPS = r.Header.Get("X-Forwarded-Proto") == "https" } else { // 本地或其他环境直接用r.TLS判断 isHTTPS = r.TLS != nil } if !isHTTPS { log.Info("Redirecting to HTTPS") targetURL := fmt.Sprintf("https://%s%s", r.Host, r.RequestURI) http.Redirect(w, r, targetURL, http.StatusMovedPermanently) return } log.Info("Not Redirecting to HTTPS") next.ServeHTTP(w, r) }) }
这样你的代码就能在CF和本地环境都正确识别请求协议,完成HTTPS重定向了。
内容的提问来源于stack exchange,提问作者MANOJ
相关产品推荐
相关产品推荐

