Правильный способ получения клиентских IP-адресов из http.Request
Какой правильный способ получить все IP-адреса клиентов от http.Request
? В PHP
есть много переменных, которые я должен проверить. Это то же самое на Go?
Я обнаружил, что:
req.RemoteAddr
И чувствителен ли запрос? например, x-forwarded-for
совпадает с x-forwarded-for
и x-forwarded-for
? (от req.Header.Get("X-FORWARDED-FOR")
)
Ответы
Ответ 1
Глядя на 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: порт" ), который является адресом исходного запроса или последнего прокси-сервера (например, балансировщик нагрузки, который живет в перед вашим сервером).
Это все, что у вас есть.
Затем вы можете исследовать заголовки, которые нечувствительны к регистру (согласно приведенной выше документации), что означает, что все ваши примеры будут работать и дают тот же результат:
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, используемого на удаленной стороне, хотя клиент может поместить что-нибудь там, если захочет. Также обратите внимание, что ожидаемый формат этого поля представляет собой список адресов 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
Ответ 2
Здесь полностью рабочий пример
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))
}
Ответ 3
В PHP есть много переменных, которые я должен проверить. Это то же самое на Go?
Это не имеет никакого отношения к Go (или PHP, если на то пошло). Это зависит от того, что отправляет клиент, прокси, балансировка нагрузки или сервер. Получите тот, который вам нужен, в зависимости от вашей среды.
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
Ответ 4
Вот как я придумала 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
- Удаленный адрес - в крайнем случае (обычно это не надежно, так как это может быть последний IP-адрес или если это пустой HTTP-запрос к серверу, т.е. Нет балансировщика нагрузки)
Ответ 5
Это сработало для меня. Я запустил 8081 и сделал запрос от порта 8080.
fmt.Printf("r: %+v\n", r) // Print all fields that you get in request
Вывод:
r: & {Метод: POST URL:/email Прото: HTTP/1.1 ProtoMajor: 1 ProtoMinor: 1 Заголовок: карта [User-Agent: [Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/602.2.11 (KHTML, как и Gecko) Версия /10.0.1 Safari/602.2.11] Accept-Language: [en-us] Accept-Encoding: [gzip, deflate] Соединение: [keep-alive] Accept: [/] Referer: [http://127.0.0.1:8080/] Content-Length: [9] Content-Type: [применение/х-WWW-форм-urlencoded; charset = UTF-8] Происхождение: [http://127.0.0.1:8080]] Тело: 0xc420012800 ContentLength: 9 TransferEncoding: [] Закрыть: false Хост: 127.0.0.1: 8081 Форма: map [] PostForm: map [] MultipartForm: Трейлер: map [] RemoteAddr: 127.0.0.1: 62232 RequestURI:/email TLS: Отменить: ответ: ctx: 0xc420017860}
У рефератора и источника есть мой клиентский IP-адрес.
ip := r.Referer() // Get Referer value
fmt.Println(ip) // print ip
Вывод:
http://127.0.0.1:8080/