Eth*_*han 5 url http url-scheme go
在Ruby / Rack中,我可以从获取当前请求URL的方案scheme#request。但是,在Go中,http.Request.URL.Scheme返回一个空字符串:
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
http.HandleFunc("/", handler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "%#v\n", r.URL.Scheme) // Always shows empty string
}
Run Code Online (Sandbox Code Playgroud)
如何获得当前请求URL的方案?
Isa*_*ten 11
要提供HTTP和HTTPS服务,您需要调用两个服务函数
http.ListenAndServe()并使用相同的http.ListenAndServeTLS()处理程序,因为如果您仅使用其中 1 个(如问题示例),那么您仅列出http和HTTPShttp.ListenAndServe()的1 个协议,如果您将尝试使用它不会通过的不同协议来联系服务器,http.ListenAndServeTLS()
因为HTTPS是基于 TLS 的 HTTP,所以*http.Request有一个TLS属性可以返回*tls.ConnectionState有关此请求中使用的 TLS 的信息,那么如果您想知道客户端如何联系服务器,您可以检查请求TLS属性,如果请求是通过HTTPS发出的,它不会为零,如果请求是通过HTTP发出的,则该TLS属性将为nil,因为使用 TLS 发出请求的唯一方式是使用HTTPS协议
func handler(w http.ResponseWriter, r *http.Request) {
if r.TLS == nil {
// the scheme was HTTP
} else {
// the scheme was HTTPS
}
}
func main() {
http.HandleFunc("/", handler)
go func(){
log.Fatal(http.ListenAndServeTLS(":8443","localhost.crt", "localhost.key", nil))
}()
log.Fatal(http.ListenAndServe(":8080", nil))
}
Run Code Online (Sandbox Code Playgroud)
一个快速grep显示,r.URL.Scheme除了net/http. 我个人认为应该尽可能,但显然我有少数意见。
如果您自己打开了一个 TLS 侦听器,http.ListenAndServeTLS()那么您大概知道该方案已经是 https 了。r.URL.Scheme在这种情况下,您可以使用一个简单的中间件处理程序来填充。
func AlwaysHTTPS(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
r.URL.Scheme = "https"
next.ServeHTTP(w, r)
})
}
Run Code Online (Sandbox Code Playgroud)
如果您在 Web 服务器后面运行,则它可能会在标头中传递请求协议,例如X-Forwarded-Proto. 在这种情况下,您可以使用像 gorilla's handlers这样的处理程序。ProxyHeaders () 来填补缺失的字段。
使用 gorilla mux 的示例:
package main
import (
"log"
"net/http"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
)
func main() {
r := mux.NewRouter()
r.Use(handlers.ProxyHeaders)
http.Handle("/", r)
log.Fatal(http.ListenAndServe("[::]:8009", nil))
}
Run Code Online (Sandbox Code Playgroud)
从它的评论:
ProxyHeaders 检查常见的反向代理标头并在 HTTP 请求结构中设置相应的字段。这些是远程(客户端)IP 地址的 X-Forwarded-For 和 X-Real-IP,方案 (http|https) 的 X-Forwarded-Proto 或 X-Forwarded-Scheme 和 RFC7239 转发标头,其中可能包括客户端 IP 和方案。
注意:只有在 nginx、HAProxy 或 Apache 等反向代理后面时才应使用此中间件。不(或配置为不)从客户端请求中剥离这些标头的反向代理,或者从远程客户端“按原样”接受这些标头的反向代理(例如,当 Go 不在代理后面时),可以表现为一个漏洞如果您的应用程序使用这些标头来验证请求的“可信度”。
由于您使用ListenAndServeand not ListenAndServeTLS,因此您的方案可以安全地假定为 http。如果您同时使用 tls 和非 tls 版本,可以使用r.TLS并检查它是否为 null 来了解 TLS 是否建立。如果您的 go 应用程序在反向代理后面运行,那么您必须检查将请求转发到您的应用程序的 Web 服务器上的文档,以了解如何配置它以将此信息作为标头传递。这是一个描述nginx 配置的链接,它可以实现这一点。您还可以轻松找到其他网络服务器的配置指南。
更好的是,在主 Web 服务器上配置HSTS,这样您就不必完全担心不安全的连接。非 TLS http 的合法用途(如果有的话)也很少。对于 nginx,您会发现这篇文章很有用。对于其他网络服务器,您也可以轻松找到配置指南。
如果您不确定您的网站/应用程序是否需要 https,我建议您阅读此内容。
Bri*_*rij -2
这是因为,您正在访问 HTTP 服务器,因此:
GET / HTTP/1.1
Host: localhost:8080
Run Code Online (Sandbox Code Playgroud)
在这种情况下,基于解析您得到的是来自 Go 的 http.Request.URL 的原始 URL。之所以会出现这种情况,是因为您是从相对路径访问 URL,因此 URL 对象中缺少 Host 或 Scheme。
如果您确实想获取 HTTP 主机,则可能必须访问 http.Request 结构的 Host 属性。请参阅http://golang.org/pkg/http/#Request
因为它不是直接可用的,但您仍然可以组装它:
u := r.URL
// The scheme can be http/https because that's depends on protocol your server handles.
u.Scheme = "http"
Run Code Online (Sandbox Code Playgroud)