问题现象
在本地使用 localhost / 127.0.0.1 进行开发测试时,发现 ICE 候选地址为 mDNS 类型,导致 ICE 通讯异常。
具体表现为:WebRTC 建立连接时,onicecandidate 回调中拿到的候选地址形如 xxxx.local,而不是预期的 192.168.x.x 或 127.0.0.1。由于 mDNS 主机名需要在局域网内通过多播解析,在部分环境(如跨网段、容器网络、部分移动端浏览器、内网 DNS 受限等)下无法解析成功,最终导致 ICE 收集不到可用候选,连接一直停留在 checking 状态或直接失败。
背景知识
什么是 mDNS 候选地址
Chrome 从 76 版本开始,默认开启「隐藏本地 IP」策略:当页面使用 WebRTC 时,浏览器会把本地内网 IP 替换为随机生成的 mDNS 主机名(如 a1b2c3d4-xxxx-xxxx-xxxx-xxxxxxxxxxxx.local),只有同一局域网内、同样支持 mDNS 解析的对端才能还原出真实 IP。
这一策略的初衷是保护用户隐私,避免网站通过 WebRTC 获取用户的内网 IP 与网络拓扑。但在本地开发、内网联调、自建信令服务等场景下,反而会带来额外的连通性问题。
常见触发场景
- 本地
localhost/127.0.0.1与远端服务联调,双方不在同一 mDNS 广播域内。 - 使用 Docker、虚拟机或 WSL 等网络隔离环境,多播报文无法正常转发。
- 部分 Android / iOS 浏览器或内嵌 WebView 对 mDNS 解析支持不完整。
- 企业内网禁用了多播(Multicast)或 mDNS(UDP 5353)端口。
解决方案
可以仅关闭浏览器的 mDNS 候选地址隐藏功能,具体操作如下。
在浏览器地址栏输入:
text
chrome://flags/#enable-webrtc-hide-local-ips-with-mdns
将该选项设置为 Disabled,然后重启浏览器即可。

验证是否生效
重启浏览器后,重新发起一次 WebRTC 连接,在 onicecandidate 回调中打印候选信息:
javascript
const pc = new RTCPeerConnection({
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
});
pc.onicecandidate = (event) => {
if (event.candidate) {
console.log('candidate:', event.candidate.candidate);
}
};
如果输出中不再出现 .local 结尾的主机名,而是正常的 IPv4 地址,说明配置已生效。
其他可选方案
如果无法修改浏览器 Flag(例如线上环境、用户侧浏览器不受控),可以考虑以下替代思路:
- 配置 TURN 服务:通过 TURN 中继转发媒体流,绕开候选地址解析问题,适用于 NAT 穿透失败的场景。
- 使用固定 ICE 服务器 :在
iceServers中同时配置 STUN 与 TURN,提高候选收集成功率。 - 内网部署 mDNS 反射/中继:在跨网段场景下让 mDNS 报文能够互通,但配置成本较高。
- 改用非 WebRTC 传输:如 WebSocket 直连或 HTTP 流式传输,视业务实时性要求而定。
注意事项
- 该 Flag 仅影响本机浏览器,属于开发调试手段,不建议引导终端用户修改。
- 关闭后浏览器会暴露真实内网 IP,存在一定隐私风险,请在可信网络环境下使用。
- 不同 Chrome 版本中 Flag 名称可能变化,若地址失效可在
chrome://flags中搜索mdns查找对应项。 - Edge、Chrome 等 Chromium 内核浏览器均适用;Firefox 的对应策略为
media.peerconnection.ice.obfuscate_host_addresses,可在about:config中调整。
小结
本地开发时 ICE 候选变成 mDNS 地址,本质是浏览器隐私策略与内网联调需求之间的冲突。通过关闭 chrome://flags/#enable-webrtc-hide-local-ips-with-mdns 即可快速恢复真实 IP 候选,配合候选日志验证与 TURN 兜底方案,可以覆盖绝大多数本地与内网调试场景。
解决方案
可以仅关闭浏览器的 mDNS 候选地址隐藏功能,具体操作如下。
在浏览器地址栏输入:
text
chrome://flags/#enable-webrtc-hide-local-ips-with-mdns
将该选项设置为 Disabled,然后重启浏览器即可。
