如何设置 X-Forwarded-For 和 httputil.ReverseProxy
How to set X-Forwarded-For with httputil.ReverseProxy
我为什么要这样做
这个问题我已经 运行 两次了。
第一次是使用位于仅 IPv6 服务器网络内的反向代理。客户端请求通过 NAT46 传入。请求的source-IP变为[固定96位前缀]+[32位客户端IPv4地址]。这意味着反向代理始终可以识别真实的客户端 IP。不过,我找不到将 X-Forwarded-For
header 设置为该地址的方法。我通过修改后端服务器解决了这个问题。
这次我有一个反向代理,它将 运行 在 Google App Engine 上。请求首先到达 Google 的负载均衡器,它添加 X-Forwarded-For
header 并将请求转发到我的应用程序。我想稍微修改一下请求,然后将其传递给后端服务器,我无法修改。 back-end 需要原始客户端 IP,并且可以通过 X-Forwarded-For
接受它(它已通过身份验证,不用担心)。在这种情况下,我想通过未修改的 Google 负载均衡器传递 X-Forwarded-For
header。
问题
似乎无法将 X-Forwarded-For
设置为我在使用 httputil.ReverseProxy
时选择的值。如果我设置它(下面的选项 1),将附加来自 TCP 连接的客户端地址。如果我将它设置为 nil
(下面的选项 2),它会像文档中建议的那样被省略,但这也不是我想要的。
package main
import (
"log"
"net/http"
"net/http/httputil"
)
func director(req *http.Request) {
// currently running a PHP script that just records headers
host := "bsweb02.bentonvillek12.org"
// who we dial
req.URL.Scheme = "https"
req.URL.Host = host
// host header
req.Host = host
// proof that most headers can be passed through fine
req.Header["Foo"] = []string{"Bar"}
req.Header["X-Forwarded-For"] = []string{"1.2.3.4"} // option 1
//req.Header["X-Forwarded-For"] = nil // option 2
}
func main() {
http.ListenAndServe(":80", &httputil.ReverseProxy{
Director: director,
})
}
选项 1
array(9) {
["Content-Type"]=>
string(0) ""
["Content-Length"]=>
string(1) "0"
["Foo"]=>
string(3) "Bar"
["X-Forwarded-For"]=>
string(18) "1.2.3.4, 127.0.0.1"
["User-Agent"]=>
string(11) "curl/7.81.0"
["Host"]=>
string(26) "bsweb02.bentonvillek12.org"
["Accept-Encoding"]=>
string(4) "gzip"
["Accept"]=>
string(3) "*/*"
["Connection"]=>
string(5) "close"
}
选项 2
array(8) {
["Content-Type"]=>
string(0) ""
["Content-Length"]=>
string(1) "0"
["Foo"]=>
string(3) "Bar"
["User-Agent"]=>
string(11) "curl/7.81.0"
["Host"]=>
string(26) "bsweb02.bentonvillek12.org"
["Accept-Encoding"]=>
string(4) "gzip"
["Accept"]=>
string(3) "*/*"
["Connection"]=>
string(5) "close"
}
我相信你有两个选择。
1。实施 http.RoundTripper
您可以在其中实现自己的 RoundTripper
和 re-set X-Forwarded-For
。 (demonstration)
type MyRoundTripper struct{}
func (t *MyRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
req.Header["X-Forwarded-For"] = []string{"1.2.3.4"}
return http.DefaultTransport.RoundTrip(req)
}
func main() {
http.ListenAndServe(":80", &httputil.ReverseProxy{
Director: director,
Transport: &MyRoundTripper{},
})
}
当 Transport
字段未在 httputil.ReverseProxy
上设置时,它会回退到 http.DefaultTransport
,因此您也可以在自定义代码后回退到它。
2。取消设置 req.RemoteAddr
您在调用反向代理之前重置了原始请求的 RemoteAddr
字段。此字段由 HTTP 服务器设置,如果存在,将触发反向代理实现中的 X-Forwarded-For
替换。 (demonstration)
func main() {
http.ListenAndServe(":80", func(w http.ResponseWriter, r *http.Request) {
r.RemoteAddr = ""
proxy := &httputil.ReverseProxy{ Director: director }
proxy.ServeHTTP(w, r)
})
}
但是,此行为依赖于实现细节,将来可能会或可能不会更改。我建议改为使用选项 1。
我为什么要这样做
这个问题我已经 运行 两次了。
第一次是使用位于仅 IPv6 服务器网络内的反向代理。客户端请求通过 NAT46 传入。请求的source-IP变为[固定96位前缀]+[32位客户端IPv4地址]。这意味着反向代理始终可以识别真实的客户端 IP。不过,我找不到将 X-Forwarded-For
header 设置为该地址的方法。我通过修改后端服务器解决了这个问题。
这次我有一个反向代理,它将 运行 在 Google App Engine 上。请求首先到达 Google 的负载均衡器,它添加 X-Forwarded-For
header 并将请求转发到我的应用程序。我想稍微修改一下请求,然后将其传递给后端服务器,我无法修改。 back-end 需要原始客户端 IP,并且可以通过 X-Forwarded-For
接受它(它已通过身份验证,不用担心)。在这种情况下,我想通过未修改的 Google 负载均衡器传递 X-Forwarded-For
header。
问题
似乎无法将 X-Forwarded-For
设置为我在使用 httputil.ReverseProxy
时选择的值。如果我设置它(下面的选项 1),将附加来自 TCP 连接的客户端地址。如果我将它设置为 nil
(下面的选项 2),它会像文档中建议的那样被省略,但这也不是我想要的。
package main
import (
"log"
"net/http"
"net/http/httputil"
)
func director(req *http.Request) {
// currently running a PHP script that just records headers
host := "bsweb02.bentonvillek12.org"
// who we dial
req.URL.Scheme = "https"
req.URL.Host = host
// host header
req.Host = host
// proof that most headers can be passed through fine
req.Header["Foo"] = []string{"Bar"}
req.Header["X-Forwarded-For"] = []string{"1.2.3.4"} // option 1
//req.Header["X-Forwarded-For"] = nil // option 2
}
func main() {
http.ListenAndServe(":80", &httputil.ReverseProxy{
Director: director,
})
}
选项 1
array(9) {
["Content-Type"]=>
string(0) ""
["Content-Length"]=>
string(1) "0"
["Foo"]=>
string(3) "Bar"
["X-Forwarded-For"]=>
string(18) "1.2.3.4, 127.0.0.1"
["User-Agent"]=>
string(11) "curl/7.81.0"
["Host"]=>
string(26) "bsweb02.bentonvillek12.org"
["Accept-Encoding"]=>
string(4) "gzip"
["Accept"]=>
string(3) "*/*"
["Connection"]=>
string(5) "close"
}
选项 2
array(8) {
["Content-Type"]=>
string(0) ""
["Content-Length"]=>
string(1) "0"
["Foo"]=>
string(3) "Bar"
["User-Agent"]=>
string(11) "curl/7.81.0"
["Host"]=>
string(26) "bsweb02.bentonvillek12.org"
["Accept-Encoding"]=>
string(4) "gzip"
["Accept"]=>
string(3) "*/*"
["Connection"]=>
string(5) "close"
}
我相信你有两个选择。
1。实施 http.RoundTripper
您可以在其中实现自己的 RoundTripper
和 re-set X-Forwarded-For
。 (demonstration)
type MyRoundTripper struct{}
func (t *MyRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
req.Header["X-Forwarded-For"] = []string{"1.2.3.4"}
return http.DefaultTransport.RoundTrip(req)
}
func main() {
http.ListenAndServe(":80", &httputil.ReverseProxy{
Director: director,
Transport: &MyRoundTripper{},
})
}
当 Transport
字段未在 httputil.ReverseProxy
上设置时,它会回退到 http.DefaultTransport
,因此您也可以在自定义代码后回退到它。
2。取消设置 req.RemoteAddr
您在调用反向代理之前重置了原始请求的 RemoteAddr
字段。此字段由 HTTP 服务器设置,如果存在,将触发反向代理实现中的 X-Forwarded-For
替换。 (demonstration)
func main() {
http.ListenAndServe(":80", func(w http.ResponseWriter, r *http.Request) {
r.RemoteAddr = ""
proxy := &httputil.ReverseProxy{ Director: director }
proxy.ServeHTTP(w, r)
})
}
但是,此行为依赖于实现细节,将来可能会或可能不会更改。我建议改为使用选项 1。