request()->ip() 需先配置 trusted_proxies 并设置内网段(如 ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16'])及 SLB/CDN 回源 IP 段,确保其解析真实 IP;再于中间件中用 filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) 判断内外网,结果存为请求属性供全局使用。

如何用 request()->ip() 区分内外网访问
直接调用 request()->ip() 拿到的 IP 很可能不是真实客户端地址,而是反向代理、CDN 或 SLB 的内网地址。不配置可信代理列表,request()->ip() 默认只信任 127.0.0.1 和 ::1,线上环境几乎必然返回网关 IP。
必须在 config/app.php 中显式设置 'trusted_proxies',填入你实际部署的内网段:
-
['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16']—— 覆盖常见私有网段 - 若用阿里云 SLB 或腾讯云 CLB,还要加上其回源 IP 段(如
100.64.0.0/10) - Nginx 配置中确保有
proxy_set_header X-Real-IP $remote_addr;,且不允许多层透传伪造X-Forwarded-For
配置生效后,request()->ip() 才会从 X-Real-IP 或 X-Forwarded-For 最右非可信段取值,结果才可用来判断内外网。
判断逻辑写在哪——中间件是唯一合理位置
不能把判断逻辑散落在每个控制器里,更不能塞进模板或视图。接口请求统计需要统一采集、统一打标、统一落库,中间件是唯一能拦截全部 HTTP 请求且保证生命周期一致的位置。
立即学习“PHP免费学习笔记(深入)”;
新建中间件 App\Middleware\TrackNetwork,在 handle() 中做两件事:
- 调用
$ip = $request->ip();获取已校准 IP - 用 PHP 原生函数判断:
filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)返回false即为内网或保留地址 - 把结果存为请求属性:
$request->withAttr('network_type', 'internal')或'external' - 同时记录日志字段:
['ip' => $ip, 'network_type' => $type, 'trace_id' => $request->attr('trace_id')]
这样后续所有业务代码都能通过 $request->attr('network_type') 拿到分类结果,无需重复计算。
统计聚合别硬查日志文件——用 Redis 计数器实时分桶
按秒/分钟统计内外网请求数量,如果每次查日志再 grep 或 awk,性能和实时性都不可控。应利用 Redis 的原子操作做轻量级聚合。
在中间件最后阶段($next($request) 之后)执行计数:
- Key 设计:
api:network:20260817:12:22:internal(日期+小时+分钟+类型) - 命令:
$redis->incr("api:network:{$date}:{$hour}:{$minute}:{$type}") - 过期时间设为
7200秒(2 小时),避免冷 key 持久堆积 - 注意:不要用
INCRBY加大步长,防止并发漏计;单次请求只 +1
前端或监控脚本可通过 GET api:network:20260817:12:22:external 直接拿到当前分钟外部请求数,毫秒级响应。
容易被忽略的边界情况
内外网判断不是非黑即白,几个关键点常被跳过:
- IPv6 地址要单独处理:
if (strpos($ip, ':') !== false) { /* 用 inet_pton + unpack 判断是否在 fc00::/7 或 fe80::/10 */ } - SLB 回源时可能带多个
X-Forwarded-For值,但 ThinkPHP 默认只取第一个,需确认trusted_proxies是否覆盖了所有跳数 - 小程序、APP 等客户端可能走公司内网代理访问生产 API,这类流量本质是“外网身份、内网路径”,需结合
User-Agent和Referer辅助识别 - 本地开发时
php think run启动的服务默认绑定127.0.0.1,request()->ip()拿到的就是127.0.0.1,不会触发外网逻辑——这点测试时容易误判
真正上线前,务必用真实外网设备(手机切蜂窝网络)调用一次接口,抓包确认响应头和日志中记录的 network_type 是否准确。



















