js获取客户端ip地址
WebRTC 的客户 `RTCPeerConnection` 能拿到本地候选地址,这几乎是端ip地浏览器里唯一能直接获取 IP 的合法途径。但有个前提——你得先建立一个连接,客户哪怕对方根本不存在。端ip地我试过用一个不存在的客户 STUN 服务器地址,照样能触发候选生成。端ip地原理很简单:浏览器尝试建立连接时,客户会主动暴露自己的端ip地网络接口信息。
代码长这样:
function getLocalIPs() { return new Promise(resolve => { const pc = new RTCPeerConnection({ iceServers: [] }); pc.createDataChannel(''); pc.createOffer().then(offer => pc.setLocalDescription(offer)); pc.onicecandidate = e => { if (!e.candidate) return; const ip = e.candidate.candidate.match(/(\d+\.\d+\.\d+\.\d+)/); if (ip) resolve(ip[1]); }; }); } 跑起来你会看到一串形如 192.168.x.x 的客户地址——那是内网 IP。想拿公网 IP?端ip地那得靠外部服务。比如访问 `https://api.ipify.org`,客户返回的端ip地字符串就是你的公网出口地址。但这里有个坑:如果用户开了 VPN 或代理,客户拿到的端ip地是代理服务器的 IP,不是客户真实物理位置。有一次我测试,公司网络走的是新加坡节点,显示 IP 归属地在新加坡,可人明明在北京。
更麻烦的是,WebRTC 获取 IP 在 HTTPS 页面下才稳定,HTTP 页面经常静默失败。Chrome 从 2021 年起还加了限制——如果页面没有用户交互(比如点击按钮),`onicecandidate` 可能永远不触发。我踩过这个坑:页面加载完直接调用,等了 10 秒没反应,加了个按钮点击后才正常。
还有个偏门办法:利用 `` 标签加载第三方统计脚本,服务端记录请求来源 IP。这本质上是靠后端解析,JS 本身不直接拿 IP。比如在页面里埋一个 1x1 像素的 GIF,请求发送到自己的服务器,然后从请求头里取 `x-forwarded-for`。但要注意,有些浏览器会隐藏这个字段,或者用户用了隐私模式。
实际项目中,我通常混合用:先尝试 WebRTC 拿内网 IP,再用外部 API 拿公网 IP,两个都失败就回退到服务器端记录。有个细节——WebRTC 返回值可能是 IPv6 格式,比如 `::ffff:192.168.1.5`,需要正则提取。另外,Safari 对 WebRTC 的候选地址格式跟 Chrome 不太一样,经常返回 `[fe80::1]` 这种,得额外处理。
别指望 100% 准确。用户禁用 WebRTC、浏览器插件拦截、或者网络环境特殊(比如某些公共 Wi-Fi 做了 NAT 隔离),都会导致获取失败。我见过一个极端案例:某银行内网用户,WebRTC 返回的是虚拟网卡地址 172.16.x.x,完全无法映射到物理位置。
最后提醒一句:获取 IP 涉及隐私,别乱用。GDPR 和《个人信息保护法》都有相关规定,如果只是做内部调试没问题,但要是用作用户画像或风控,最好先做合规评估。我自己的经验是——能用后端日志解决的,就别在前端折腾 IP。
