在Ruby / Rack中,我能够get the scheme of the current request URL from 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
}
如何获取当前请求网址的方案?
答案 0 :(得分:2)
快速grep
表示r.URL.Scheme
永远不会设置为net/http
中任何位置的空字符串以外的任何内容。我个人认为应该尽可能地,但显然我有少数意见。
如果您自己使用http.ListenAndServeTLS()
打开了TLS监听器,那么可能您知道该方案已经是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)
})
}
如果您在Web服务器后面运行,那么它可以在X-Forwarded-Proto
之类的标头中传递请求协议。在这种情况下,您可以使用像大猩猩的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))
}
来自其评论:
ProxyHeaders检查常见的反向代理头并设置HTTP请求结构中的相应字段。这些是用于远程(客户端)IP地址的X-Forwarded-For和X-Real-IP,用于该方案的X-Forwarded-Proto或X-Forwarded-Scheme(http | https)和RFC7239 Forwarded报头,其中可能包括客户端IP和方案。
注意:此中间件只能在nginx,HAProxy或Apache等反向代理后面使用。没有(或被配置为不)从客户端请求剥离这些头的反向代理,或者从远程客户端“按原样”接受这些头的情况(例如,当Go不在代理后面时),可以表现为漏洞如果您的应用程序使用这些标头来验证请求的“可信度”。
答案 1 :(得分:1)
localhost是URL
形成的特例。如果你的客户是localhost,那么它将是空的。
作为特例,如果req.URL.Host是" localhost" (有或没有端口号),然后返回一个nil URL和nil错误。
获取所需url / uri信息的方法是直接从http.Request
获取。例如:
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "%s\n", r.Host)
}
答案 2 :(得分:1)
要提供 http 和 https ,您需要同时调用这两个服务功能
http.ListenAndServe()
和http.ListenAndServeTLS()
使用相同的处理程序
因为如果您仅使用其中的一种(如问题示例),那么您只会在 http 的http.ListenAndServe()
协议和 https 的http.ListenAndServeTLS()
协议中列出>,如果您尝试使用其他协议与服务器联系,那么它将无法通过
,并且由于 https 是HTTP over TLS,因此*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))
}
答案 3 :(得分:0)
由于您使用ListenAndServe
而不是ListenAndServeTLS
,因此可以将您的方案安全地假定为http。如果同时使用tls和非tls版本,则可以使用r.TLS
并将其检查为null以了解是否已建立TLS。如果您的go应用程序在反向代理后面运行,则实际上无法知道该方案是什么。
答案 4 :(得分:0)
http标头X-Forwarded-Proto将具有http或https
答案 5 :(得分:-2)
这是因为您正在访问HTTP服务器,所以:
GET / HTTP/1.1
Host: localhost:8080
在这种情况下,基于解析你得到的是来自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"