http.Request
からすべてのクライアントのIPアドレスを取得する正しい方法は何ですか? PHP
には、チェックする必要のある 変数 がたくさんあります。 Goでも同じですか?
私が見つけたものは:
req.RemoteAddr
リクエストの大文字と小文字は区別されますか?たとえば、x-forwarded-for
はX-Forwarded-For
およびX-FORWARDED-FOR
?と同じです。 (req.Header.Get("X-FORWARDED-FOR")
から)
http.Request を見ると、次のメンバー変数を見つけることができます。
// HTTP defines that header names are case-insensitive.
// The request parser implements this by canonicalizing the
// name, making the first character and any characters
// following a hyphen uppercase and the rest lowercase.
//
// For client requests certain headers are automatically
// added and may override values in Header.
//
// See the documentation for the Request.Write method.
Header Header
// RemoteAddr allows HTTP servers and other software to record
// the network address that sent the request, usually for
// logging. This field is not filled in by ReadRequest and
// has no defined format. The HTTP server in this package
// sets RemoteAddr to an "IP:port" address before invoking a
// handler.
// This field is ignored by the HTTP client.
RemoteAddr string
RemoteAddr
を使用して、リモートクライアントのIPアドレスとポート(形式は「IP:port」)を取得できます。これは元のリクエスターまたは最後のプロキシ(たとえば、サーバーの前にあるロードバランサー)。
これはあなたが確かに持っているすべてです。
次に、ヘッダーを調査できます。ヘッダーはcase-insensitive(上記のドキュメントごと)です。つまり、すべての例が機能し、同じ結果が得られます。
req.Header.Get("X-Forwarded-For") // capitalisation
req.Header.Get("x-forwarded-for") // doesn't
req.Header.Get("X-FORWARDED-FOR") // matter
これは、内部的にhttp.Header.Get
がキーを正規化するためです。 (Get
経由ではなく、ヘッダーマップに直接アクセスする場合は、最初に http.CanonicalHeaderKey を使用する必要があります。)
最後に、"X-Forwarded-For"
は、おそらくクライアントのIPに関する詳細情報を取得するために見たいフィールドです。ただし、クライアントは必要に応じてそこに何かを入れることができるため、これはリモート側で使用されるHTTPソフトウェアに大きく依存します。また、このフィールドの expected形式 はIPアドレスのコンマ+スペース区切りリストであることに注意してください。選択した単一のIP(おそらくリストの最初のIP)を取得するには、少し解析する必要があります。次に例を示します。
// Assuming format is as expected
ips := strings.Split("10.0.0.1, 10.0.0.2, 10.0.0.3", ", ")
for _, ip := range ips {
fmt.Println(ip)
}
生成されます:
10.0.0.1
10.0.0.2
10.0.0.3
ここに完全に動作する例
package main
import (
// Standard library packages
"fmt"
"strconv"
"log"
"net"
"net/http"
// Third party packages
"github.com/julienschmidt/httprouter"
"github.com/skratchdot/open-golang/open"
)
// https://blog.golang.org/context/userip/userip.go
func getIP(w http.ResponseWriter, req *http.Request, _ httprouter.Params){
fmt.Fprintf(w, "<h1>static file server</h1><p><a href='./static'>folder</p></a>")
ip, port, err := net.SplitHostPort(req.RemoteAddr)
if err != nil {
//return nil, fmt.Errorf("userip: %q is not IP:port", req.RemoteAddr)
fmt.Fprintf(w, "userip: %q is not IP:port", req.RemoteAddr)
}
userIP := net.ParseIP(ip)
if userIP == nil {
//return nil, fmt.Errorf("userip: %q is not IP:port", req.RemoteAddr)
fmt.Fprintf(w, "userip: %q is not IP:port", req.RemoteAddr)
return
}
// This will only be defined when site is accessed via non-anonymous proxy
// and takes precedence over RemoteAddr
// Header.Get is case-insensitive
forward := req.Header.Get("X-Forwarded-For")
fmt.Fprintf(w, "<p>IP: %s</p>", ip)
fmt.Fprintf(w, "<p>Port: %s</p>", port)
fmt.Fprintf(w, "<p>Forwarded for: %s</p>", forward)
}
func main() {
myport := strconv.Itoa(10002);
// Instantiate a new router
r := httprouter.New()
r.GET("/ip", getIP)
// Add a handler on /test
r.GET("/test", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
// Simply write some test data for now
fmt.Fprint(w, "Welcome!\n")
})
l, err := net.Listen("tcp", "localhost:" + myport)
if err != nil {
log.Fatal(err)
}
// The browser can connect now because the listening socket is open.
//err = open.Start("http://localhost:"+ myport + "/test")
err = open.Start("http://localhost:"+ myport + "/ip")
if err != nil {
log.Println(err)
}
// Start the blocking server loop.
log.Fatal(http.Serve(l, r))
}
これは私がIPを思い付く方法です
func ReadUserIP(r *http.Request) string {
IPAddress := r.Header.Get("X-Real-Ip")
if IPAddress == "" {
IPAddress = r.Header.Get("X-Forwarded-For")
}
if IPAddress == "" {
IPAddress = r.RemoteAddr
}
return IPAddress
}
X-Real-Ip-最初の真のIPを取得します(リクエストが複数のNATソース/ロードバランサーの背後にある場合)
X-Forwarded-For-何らかの理由でX-Real-Ipが空白で応答を返さない場合、X-Forwarded-Forから取得
PHPには、確認する必要のある変数がたくさんあります。 Goでも同じですか?
これには、Go(またはその場合はPHP)とは関係ないnothingがあります。それは、クライアント、プロキシ、ロードバランサー、またはサーバーが送信しているものによって異なります。環境に応じて必要なものを入手してください。
http.Request.RemoteAddr
にはリモートIPアドレスが含まれます。実際のクライアントである場合とそうでない場合があります。
リクエストの大文字と小文字は区別されますか?たとえば、x-forwarded-forはX-Forwarded-ForおよびX-FORWARDED-FORと同じですか? (req.Header.Get( "X-FORWARDED-FOR")から))
いいえ、自分で試してみませんか? http://play.golang.org/p/YMf_UBvDsH