2016-04-13 20 views
3

Golangのnet/httpパッケージを使用してHTTPサーバーを作成したいと考えています。これは、サーバーのHTTP接続のIPアドレスに依存します。golang net/httpを使用してサーバーでサーバー自身のアドレスを取得する方法は?

つまり、私が探しているのはCGIの "SERVER_ADDR"変数に相当します。

http.Requestの最も近いフィールドは「ホスト」ですが、要求がリテラルアドレスを使用する場合はアドレスと等しいため、使用できません(サーバーは名前で使用される可能性があります)。

https://golang.org/src/net/http/server.goのソースを見ると、サーバのアドレスに到達する唯一の方法は、ハンドラ内の接続をHijack()することで、後続のHTTP解析を同じ接続で実装する方法ですが、控えめに言って...

理想的なソリューションのように修正さgolang標準ライブラリ内のHTTP /リクエストとHTTP /サーバーを持っていることであろうようにそれは次のようだ:その後、

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をきれいに整理してください。

私には何かがありません。これを行うにはよりクリーンな方法がありますか?

答えて

1

個人的には、私は他の方法で得ることのできる何かのために標準ライブラリのものを変更しません。すべての接続からそれを解析する利点がありますか?

おそらくもっと簡単な方法がありますが、次のようなことがあります。

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 
} 
+0

私の使用の場合、接続ごとに異なる可能性があるため、単一のアドレスは機能しません。大量のIPv6アドレスが適用された単一のインターフェースを考えてみましょう。接続は、それらのいずれかで終了することができ、私はそれがどれだったかを知る必要があります... –

関連する問題