ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

浏览器获取客户端IP、MAC和主机名的7种方法及原理详解

浏览器获取客户端IP、MAC和主机名的7种方法及原理详解 简介JS 获取客户端 IP、MAC 与主机名历来是前端开发中的棘手需求。作者整理的这份 PDF 汇总了 7 类可行方法面向需要实现个性化服务、地域定位或安全校验的开发者从兼容 IE 的 ActiveX 对象到新浪、搜狐、太平洋电脑网等第三方接口再到 WebRTC 内网 IP 探测与 HTTP 头字段解析每种方法都给出代码示例并说明适用平台、局限与隐私风险。资源仅含 1 个 PDF 文件压缩包 56KB轻量易读适合作为速查手册嵌入日常项目笔记。目前已有 2054 人浏览学习说明该主题在实践中有较高关注度。文档特别澄清了 MAC 地址和主机名在浏览器环境中的不可直接获取性能帮助开发者避开已废弃的 ActiveX 方案减少跨浏览器调试与多源检索的时间成本也提醒应始终关注接口的兼容性与可持续性。 做了好几年 Web 开发隔三差五就有人拿着“JS 获取客户端 IP 地址、MAC 和主机名”的需求过来问要搞用户登录日志、要做设备绑定、要统计异常访问……我特别理解这种诉求但也很无奈浏览器安全模型已经把路堵得差不多了。这篇文章我就把目前还能用的、半只脚踩在合规边缘的、以及彻底成为历史的方法一次性整理出来共 7 个顺便把原理和坑都讲透。1. 先泼冷水现代浏览器到底能拿到哪些信息1.1 能拿到和拿不到的信息先说结论方便你决定要不要往下读IP 地址能拿到但要区分“公网 IP”和“内网 IP”。公网 IP 可以通过第三方接口或自建后端拿内网 IP 在 Chrome 76 版本之后被 mDNS 隐私策略隐藏拿到的很可能是一串xxxx.local的假主机名。MAC 地址浏览器层面完全拿不到没有任何公开 API。唯一能拿到的 ActiveX 方案也只活在 20 年前的 IE 时代。主机名要看你怎么定义。location.hostname拿到的是“当前网站的域名”不是访问者电脑的设备名。客户端真实设备名在现代浏览器里同样拿不到。也就是说如果你在 2025 年做纯前端页面想用浏览器自身能力直接拿到用户电脑 MAC 和计算机名答案就两个字没门。后面的方法要么是后端配合要么是“曲线救国”。1.2 为什么厂商都在疯狂封堵每次聊这个话题我都喜欢拿快递员做个类比你的浏览器就像一个对外只开放一个小窗口的快递站别人想通过窗口知道“站内电脑的网卡编号”窗口管理员直接拒绝。浏览器厂商封堵 MAC、内网 IP 这些信息核心原因有两个隐私保护和反指纹追踪。MAC 地址全球唯一如果网页能随意读取那用户不管换网络、换设备厂商都能精准识别跨站追踪会变得可怕。内网 IP 也一样它会暴露你的局域网结构、路由器品牌、设备数量。所以从 Chrome 76 开始WebRTC 的 ICE Candidate 会被替换成随机字符串原始 IP 不再直接暴露。这不是 bug是有意为之。明确了这些边界下面这 7 个方法就好理解了。2. 方法一WebRTC ICE 挖出内网 IP2.1 原理说明WebRTC 在建立 P2P 连接时需要收集本地网络候选地址ICE Candidate这个过程会暴露本机网卡上的 IP。早期版本 Chrome、Firefox 都会直接返回192.168.x.x这种地址于是在 2015 年前后“用 WebRTC 获取本地 IP”成了前端圈的热门技巧。具体原理是创建一个 RTCPeerConnection添加一个 DataChannel然后调用createOffer并setLocalDescription浏览器就会主动去采集本机 IP并通过onicecandidate回调返回给页面。页面只需要解析 candidate 字符串里的ip:字段。2.2 代码实现与 mDNS 大坑核心代码长这样function parseCandidate(candidate) { const match candidate.match(/ip:\s*([^\s])/i); return match ? match[1] : null; } async function getLocalIP() { return new Promise((resolve) { try { const pc new RTCPeerConnection({ iceServers: [] }); const ips new Set(); pc.onicecandidate (e) { if (!e.candidate) { resolve([...ips]); return; } const ip parseCandidate(e.candidate.candidate); if (ip) ips.add(ip); }; pc.createDataChannel(probe); pc.createOffer() .then((offer) pc.setLocalDescription(offer)) .catch(() resolve([])); // 兜底3 秒超时返回 setTimeout(() resolve([...ips]), 3000); } catch { resolve([]); } }); } getLocalIP().then((ips) console.log(Local IPs:, ips));这段代码在 2020 年以前的浏览器里能稳定返回192.168.x.x或10.x.x.x。但在新版 Chrome 里你大概率会看到Local IPs: [c9744b52-5d1e-4d7e-9f0f-3f8c3c5e974d.local]这就是 mDNS 策略真实 IP 被替换成了随机的.local名称。虽然某些老版本 Chromium 或 WebView 里还能碰运气拿到真实 IP但已经不能当成可靠方案了。我的建议是只有在你确定目标用户都使用旧浏览器内核比如企业内部老 WebView 应用时才考虑这个方案。3. 方法二第三方 IP 接口拿公网 IP3.1 常用接口盘点如果只是想知道用户访问互联网时的出口 IP直接用第三方接口是最省事的。很多站点本身就提供免费接口常见的有https://api.ipify.org?formatjsonhttps://ip.sb/jsonhttps://myip.ipip.nethttps://ipinfo.io/json这些接口返回的都是 JSON 或文本直接fetch就能用。比如async function getPublicIP() { const res await fetch(https://api.ipify.org?formatjson); const data await res.json(); return data.ip; }3.2 JSONP 与跨域注意事项有些老项目不支持 fetch或接口没有配置 CORS 头那就得用 JSONP 方式。以ipify为例它支持 JSONP 回调function getPublicIPByJSONP() { return new Promise((resolve, reject) { const script document.createElement(script); script.src https://api.ipify.org?formatjsonpcallbackhandleIPCallback; window.handleIPCallback (data) { resolve(data.ip); script.remove(); }; script.onerror () { reject(new Error(JSONP load failed)); script.remove(); }; document.head.appendChild(script); }); }用 JSONP 时有个细节回调函数名要全局唯一否则多页面并发时会互相覆盖。建议在回调名后拼接随机数用完立刻删除。这类第三方接口的缺点是明显且致命的不同接口可用性不稳定有些需要 HTTPS有些域名在国内访问时快时慢接口随时可能限流或关停公网 IP 是企业出口 IP 时拿到的不是用户真实内网地址。所以生产环境务必加超时和失败兜底绝不能因为接口挂了就阻塞整个页面逻辑。4. 方法三自建后端接口让服务端告诉你客户端的 IP4.1 原理说明几乎所有“想要 IP”的真实需求最终都应该由后端解决。因为服务端拿到的是 TCP 连接的对端地址天然可信。浏览器只需要向后端发一个请求后端把 IP 放在响应体里返回即可。这种方法不依赖任何第三方也不会被浏览器隐私策略干扰。4.2 Node.js 实现示例用 Node.js 写个最简单的接口const http require(http); http.createServer((req, res) { // 注意经过 Nginx 等反向代理后remoteAddress 是代理的 IP // 需要取 X-Forwarded-For 或 X-Real-IP const ip req.headers[x-forwarded-for] ? req.headers[x-forwarded-for].split(,)[0].trim() : req.socket.remoteAddress.replace(/^::ffff:/, ); res.setHeader(Content-Type, application/json); res.end(JSON.stringify({ ip })); }).listen(3000, () { console.log(Server running on port 3000); });前端调用就非常简单了const res await fetch(/api/ip); const data await res.json(); console.log(data.ip);4.3 WebSocket 方式也不难如果项目已经用 WebSocket 做长连接那更简单。连接建立时后端在connection事件里直接拿到req.socket.remoteAddress然后用send把 IP 推给客户端就行。这种方式适合需要实时保存用户在线 IP 的业务比如风控、在线客服、多人协作系统。我自己踩过最大的坑是忘了处理代理头。如果项目前面有 Nginx、SLB 或 CDN却直接使用socket.remoteAddress拿到的全是代理服务器 IP所有用户看起来都来自同一个地址。正确做法是信任反向代理传递的X-Forwarded-For或X-Real-IP但与此同时要注意不要无脑信任客户端传进来的头必须在 Nginx 层统一覆盖这些头否则用户可以伪造 IP。5. 方法四ActiveX 老方案获取 IP、MAC、主机名的上古神器5.1 代码长什么样在 IE 6-IE 9 时代ActiveX 是 Web 页面调用本地系统组件的主要方式。通过 WMI 脚本控件可以拿到网卡 MAC、IP、计算机名。代码如下script typetext/javascript try { var locator new ActiveXObject(WbemScripting.SWbemLocator); var service locator.ConnectServer(., root\\cimv2); var { jb51: query } { jb51: undefined }; var query service.ExecQuery( SELECT MACAddress, IPAddress, DNSHostName FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled TRUE ); var e new Enumerator(query); for (; !e.atEnd(); e.moveNext()) { var item e.item(); console.log(MAC:, item.MACAddress); console.log(IP:, item.IPAddress); console.log(HostName:, item.DNSHostName); } } catch (err) { console.log(ActiveX not available, err); } /script5.2 为什么现在彻底不可用ActiveX 能拿到信息是因为它本质上调用了本地 COM 组件权限等同于本机程序。但正因如此IE 每次都会弹黄色安全条提示用户“是否允许运行 ActiveX 控件”用户体验很差。而且这个 API 从 IE11 开始就被微软弃用新版 Edge 根本不支持Chrome 和 Firefox 更是从来都没支持过。现在再提 ActiveX更多是记忆考古或企业内部老系统维护时才可能用到。如果你是要给 Windows 域环境下的老系统写运维脚本用 ActiveX 还有讨论价值其他场景可以直接跳过这个方法。6. 方法五到方法七其他可以一试的路子6.1 方法五在反向代理层获取 IP 并返回响应头这个思路适合不想写后端逻辑、只想在 Nginx 或 OpenResty 层面完成 IP 采集的场景。Nginx 里可以这样配置一个简单接口location /client-ip { add_header X-Client-IP $remote_addr always; add_header X-Client-IP-Forwarded $http_x_forwarded_for always; return 200; }前端只需要fetch(/client-ip)然后从响应头里读取X-Client-IPconst res await fetch(/client-ip); const ip res.headers.get(X-Client-IP); console.log(ip);它的本质和后端方法是相同的优点是不污染业务代码缺点是你得具备 Nginx 配置权限。注意add_header后必须加always否则只在返回特定状态码时才会输出头这是很多人容易踩的坑。6.2 方法六利用网络诊断类接口获取出口 IP 和位置信息第三方 IP 接口不只可以返回 IP有些还会附带 ASN、经纬度、时区等信息。比如 Cloudflare 的https://1.1.1.1/cdn-cgi/trace返回的是纯文本ip203.0.113.5 locCN coloHKG前端用fetch拿回来解析即可const res await fetch(https://1.1.1.1/cdn-cgi/trace); const text await res.text(); const kv Object.fromEntries(text.split(\n).map((line) line.split())); console.log(kv.ip, kv.loc);这类接口的好处是信息量大可以直接拿到国家地区码适合做强制的区域访问控制或分析面板。缺点也是第三方依赖。如果目标用户集中在某些特殊网络环境这类公共接口的连通性可能并不理想生产环境慎用。6.3 方法七设备指纹方案用唯一 ID 替代 MAC 和主机名如果你真正想要的不是“MAC 地址”这个数据而是“识别同一台设备”那设备指纹是目前唯一靠谱的替代方案。原理是综合浏览器的 Canvas 渲染结果、WebGL 参数、字体列表、屏幕分辨率、时区、UA 等信息生成一个不可逆的哈希字符串。由于不同设备在这些维度上的组合很难完全一样所以生成的指纹可以作为设备唯一标识。一个简化思路是function getFingerprint() { const canvas document.createElement(canvas); const ctx canvas.getContext(2d); ctx.textBaseline top; ctx.font 16px Arial; ctx.fillText(fingerprint- navigator.userAgent, 2, 2); const dataUrl canvas.toDataURL(image/png); // 再配合其他信息做 hash return simpleHash(navigator.userAgent dataUrl); }实际产品里我建议用社区现成库比如 FingerprintJS。它会帮你处理 Canvas、AudioContext、WebGL 等多个维度生成稳定度不错的 visitorId。再配合 LocalStorage 或 IndexedDB 缓存就能实现“同一浏览器多次访问对应同一个 ID”的效果。需要说明的是这不是 MAC也无法复原 MAC但对于登录设备管理、恶意刷接口识别等业务场景完全够用。而且从隐私合规角度看哈希指纹比直接读取 MAC 更容易通过法务审核。7. 七方法汇总对比与避坑指南7.1 速查表方法能拿到什么实现成本可靠性核心限制1. WebRTC ICE内网 IP可能被 mDNS 替代低一般新版浏览器被隐蔽2. 第三方 IP 接口公网 IP低中依赖第三方可能限流3. 自建后端接口公网/内网 IP中高需要后端配合4. ActiveX WMIIP、MAC、主机名极低极低仅老 IE 可用5. Nginx 响应头客户端 IP低高需要网关配置权限6. 网络诊断接口出口 IP、位置信息低中部分网络不可达7. 设备指纹设备唯一 ID中高非真实 MAC有隐私风险7.2 真实业务落地建议如果老板或产品经理提这个需求我一般先反问一句你要 IP、MAC、主机名的最终目的是什么是想展示给用户看还是记录日志还是识别设备仅展示公网 IP后端接口方案最稳10 分钟能搞定。需要局域网 IP先确认用户浏览器环境是否可控如果都是企业内网自研 WebView可以试试 WebRTC 方案。识别设备千万别硬碰 MAC直接用设备指纹方案省心又省力。后端日志采集优先在 Nginx 或网关层记录$remote_addr把X-Forwarded-For处理干净。这里再说几个我实际踩过的坑。第一X-Forwarded-For千万不要直接信任一定要在你的反向代理层用proxy_set_header X-Real-IP $remote_addr;覆盖掉客户端传入的伪造值否则日志里会混入大量伪造 IP。第二第三方 IP 接口必须配置超时、重试和降级否则用户网络一慢页面会卡住。第三WebRTC 获取内网 IP 的方法随着浏览器版本迭代会越来越不可用别把它写进产品硬需求里。第四做设备指纹时如果是面向欧盟或国内用户必须考虑涉及个人信息收集的合规要求建议在隐私政策里明示并给用户拒绝采集的选择。最后分享一个我一直沿用的兜底组合先调自建后端接口拿 IP取不到就走 WebRTC 拿内网 IP再不行就生成一个设备指纹存入 LocalStorage三个层级逐级降级。这样不管用户处在什么环境至少都能拿到一个可用于业务判断的标识。MAC 和计算机名这种“硬科幻”字段还是让它停留在需求文档里吧。本文还有配套的精品资源点击获取
返回列表