我想使用Golang的net / http包写一个HTTP服务器,其反应取决于HTTP连接的服务器端IP地址.
换句话说,我要找的是CGI的“SERVER_ADDR”变量.
http.Request中最接近的字段是“Host” – 但是如果请求使用文字地址,它只会等于地址,我不能使用它(服务器可能按名称使用).
查看https://golang.org/src/net/http/server.go的源代码,似乎获取服务器地址的唯一方法是Hijack()处理程序内的连接,并为同一连接上的后续请求实现后续HTTP解析,但至少可以说它非常不优雅…
看起来理想的解决方案是将golang标准库中的http / request和http / server修改如下:
diff -u go-stock-library/request.go ./request.go
--- go-stock-library/request.go 2016-04-13 17:31:48.000000000 +0200
+++ ./request.go 2016-04-13 17:32:40.000000000 +0200
@@ -227,6 +227,15 @@
// This field is ignored by the HTTP client.
RemoteAddr string
+ // LocalAddr allows HTTP servers and other software to record
+ // the network address that the request was sent to, usually for
+ // logging. This field is not filled in by ReadRequest and
+ // has no defined format. The HTTP server in this package
+ // sets LocalAddr to an "IP:port" address before invoking a
+ // handler.
+ // This field is ignored by the HTTP client.
+ LocalAddr string
+
// RequestURI is the unmodified Request-URI of the
// Request-Line (RFC 2616, Section 5.1) as sent by the client
// to a server. Usually the URL field should be used instead.
diff -u go-stock-library/server.go ./server.go
--- go-stock-library/server.go 2016-04-13 17:29:19.000000000 +0200
+++ ./server.go 2016-04-13 17:31:38.000000000 +0200
@@ -161,6 +161,13 @@
// This is the value of a Handler's (*Request).RemoteAddr.
remoteAddr string
+ // serverAddr is rwc.LocalAddr().String(). It is not populated synchronously
+ // inside the Listener's Accept goroutine, as some implementations block.
+ // It is populated immediately inside the (*conn).serve goroutine.
+ // This is the value of a Handler's (*Request).LocalAddr.
+ localAddr string
+
+
// tlsState is the TLS connection state when using TLS.
// nil means not TLS.
tlsState *tls.ConnectionState
@@ -736,6 +743,7 @@
delete(req.Header, "Host")
req.RemoteAddr = c.remoteAddr
+ req.LocalAddr = c.localAddr
req.TLS = c.tlsState
if body, ok := req.Body.(*body); ok {
body.doEarlyClose = true
@@ -1382,6 +1390,7 @@
// Serve a new connection.
func (c *conn) serve() {
c.remoteAddr = c.rwc.RemoteAddr().String()
+ c.localAddr = c.rwc.LocalAddr().String()
defer func() {
if err := recover(); err != nil {
const size = 64 << 10
然后以一种干净利落的方式在代码中使用新的LocalAddr.
我错过了什么,有更清洁的方法吗?
最佳答案 我个人不会修改标准库中的任何内容,因为我可以通过其他方式获得.从每个连接解析它有一些优势吗?
可能有一种更简单的方法,但我有以下几点.
func getMyInterfaceAddr() (net.IP, error) {
ifaces, err := net.Interfaces()
if err != nil {
return nil, err
}
addresses := []net.IP{}
for _, iface := range ifaces {
if iface.Flags&net.FlagUp == 0 {
continue // interface down
}
if iface.Flags&net.FlagLoopback != 0 {
continue // loopback interface
}
addrs, err := iface.Addrs()
if err != nil {
continue
}
for _, addr := range addrs {
var ip net.IP
switch v := addr.(type) {
case *net.IPNet:
ip = v.IP
case *net.IPAddr:
ip = v.IP
}
if ip == nil || ip.IsLoopback() {
continue
}
ip = ip.To4()
if ip == nil {
continue // not an ipv4 address
}
addresses = append(addresses, ip)
}
}
if len(addresses) == 0 {
return nil, fmt.Errorf("no address Found, net.InterfaceAddrs: %v", addresses)
}
//only need first
return addresses[0], nil
}