Request::ip() 默认返回代理IP而非真实IP,需正确配置TrustProxies中间件及$proxies、$headers才能解析X-forwarded-For获取真实IP,手动读取$_SERVER存在安全风险。

Request::ip() 返回的是代理IP而不是真实IP
直接调用 Request::ip() 或 $request->ip() 在有 nginx、Cloudflare、cdn 或负载均衡的环境下,通常拿到的是最后一层代理(比如 Nginx)的 IP,而非用户真实出口 IP。这是因为 http 请求头中的 X-Forwarded-For 才可能携带原始客户端 IP,而 laravel 默认不信任这些头字段。
必须配置 trusted proxies 才能解析真实 IP
Laravel 的 IP 解析逻辑依赖 Trustedproxy 中间件是否启用,以及 appHttpMiddlewareTrustProxies 中的 $proxies 和 $headers 配置。没配对的话,Request::ip() 就不会去读 X-Forwarded-For。
- 如果服务器直连用户(无任何代理),保持
$proxies = NULL即可,Request::ip()是准确的 - 如果有 Nginx 反代,把 Nginx 服务器 IP 加到
$proxies = ['127.0.0.1', '192.168.1.10'];或设为'*'(仅限内网可信环境) - 若使用 Cloudflare,需设置
$headers = Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO;,并把 Cloudflare 的 IP 段加入$proxies(或改用Cloudflare Trusted Proxy包) - 注意:Laravel 5.5+ 默认启用
TrustProxies中间件,但$proxies默认是null,等于没生效
获取真实 IP 的安全写法不是靠 $_SERVER
别手动读 $_SERVER['HTTP_X_FORWARDED_FOR'] 或拼接字符串——这容易被伪造、绕过校验、导致 IP 欺骗。Laravel 的 Request::ip() 在正确配置 TrustProxies 后,内部已做了头字段校验和多级解析(取最左非受信代理 IP),比手写更可靠。
- 正确做法:确保
AppHttpMiddlewareTrustProxies已注册在$middlewareGroups['web']中 - 检查
APP_URL和部署结构是否匹配(例如 https 被终止在 CDN,但后端没收到X-Forwarded-Proto: https,可能导致 URL 生成异常) - 调试时可用
$request->header('x-forwarded-for')查看原始头内容,但业务逻辑中仍应统一走$request->ip()
某些场景下 $request->ip() 仍返回 ::1 或 127.0.0.1
常见于本地开发用 Valet / Homestead / Sail 启动,Nginx 或 caddy 把请求转给了 php-FPM,但未正确设置 fastcgi_param REMOTE_ADDR $remote_addr,或未透传 X-Forwarded-For。这时候即使 Laravel 配置了 trusted proxy,也拿不到上游真实值。
- Valet 用户:确认
~/.config/valet/Nginx/*.test配置里有fastcgi_param REMOTE_ADDR $remote_addr; - docker 环境:检查 Nginx 容器是否将宿主机 IP 加入
proxy_set_header X-Forwarded-For,且 PHP 容器网络模式是否允许识别该头 - 用
dd($request->server('REMOTE_ADDR'), $request->header('x-forwarded-for'))对比输出,能快速定位是哪一层丢失了原始 IP
实际 IP 获取这件事,核心不在函数怎么调,而在整个请求链路上每层代理是否规范透传、Laravel 是否被明确告知“谁可信”。漏掉任意一环,Request::ip() 就只是个幻觉。