1.问题回放
使用如下代码获取局域网IP报错
(代码来源:https://github.com/diafygi/webrtc-ips 日期:2019-02-16)
1 //get the IP addresses associated with an account
2 function getIPs(callback){
3 var ip_dups = {};
4
5 //compatibility for firefox and chrome
6 var RTCPeerConnection = window.RTCPeerConnection
7 || window.mozRTCPeerConnection
8 || window.webkitRTCPeerConnection;
9 var useWebKit = !!window.webkitRTCPeerConnection;
10
11 //bypass naive webrtc blocking using an iframe
12 if(!RTCPeerConnection){
13 //NOTE: you need to have an iframe in the page right above the script tag
14 //
15 //<iframe id="iframe" sandbox="allow-same-origin" style="display: none"></iframe>
16 //<script>...getIPs called in here...
17 //
18 var win = iframe.contentWindow;
19 RTCPeerConnection = win.RTCPeerConnection
20 || win.mozRTCPeerConnection
21 || win.webkitRTCPeerConnection;
22 useWebKit = !!win.webkitRTCPeerConnection;
23 }
24
25 //minimal requirements for data connection
26 var mediaConstraints = {
27 optional: [{RtpDataChannels: true}]
28 };
29
30 var servers = {iceServers: [{urls: "stun:stun.services.mozilla.com"}]};
31
32 //construct a new RTCPeerConnection
33 var pc = new RTCPeerConnection(servers, mediaConstraints);
34
35 function handleCandidate(candidate){
36 //match just the IP address
37 var ip_regex = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/
38 var ip_addr = ip_regex.exec(candidate)[1];
39
40 //remove duplicates
41 if(ip_dups[ip_addr] === undefined)
42 callback(ip_addr);
43
44 ip_dups[ip_addr] = true;
45 }
46
47 //listen for candidate events
48 pc.onicecandidate = function(ice){
49
50 //skip non-candidate events
51 if(ice.candidate)
52 handleCandidate(ice.candidate.candidate);
53 };
54
55 //create a bogus data channel
56 pc.createDataChannel("");
57
58 //create an offer sdp
59 pc.createOffer(function(result){
60
61 //trigger the stun server request
62 pc.setLocalDescription(result, function(){}, function(){});
63
64 }, function(){});
65
66 //wait for a while to let everything done
67 setTimeout(function(){
68 //read candidate info from local description
69 var lines = pc.localDescription.sdp.split('\n');
70
71 lines.forEach(function(line){
72 if(line.indexOf('a=candidate:') === 0)
73 handleCandidate(line);
74 });
75 }, 1000);
76 }
77
78 //Test: Print the IP addresses into the console
79 getIPs(function(ip){console.log(ip);});
2.分析
代码在此处报错:pc.setLocalDescription(result, function(){}, function(){})
即此API报错:RTCPeerConnection.setLocalDescription()
源代码在Firefox和Chrome71正常执行,Chrome升级到72稳定版后代码报错,浏览器debug调试发现Chrome71和Chrome72的offer(代码中是result)的SDP格式/内容发生了变化,因此可以判断是新版本Chrome的WebRTC相关API发生了变化,于是在https://www.chromestatus.com/features找到了解释:
文中提供了此链接:https://docs.google.com/document/d/1-ZfikoUtoJa9k-GZG1daN0BU3IjIanQ_JSscHxQesvU/edit,划重点:
WebRTC规范仍然在演进,Chrome上目前SDP格式有两种:规范定义的SDP格式(Unified Plan)和Chrome自己定义的SDP格式(Plan B),火狐支持前者,如果不指定SDP格式Chrome72默认使用Unified Plan,这和Chrome71的行为不同,那么如何指定SDP格式呢?
3.解决
将源代码此行
var servers = {iceServers: [{urls: "stun:stun.services.mozilla.com"}]};
更改为
var servers = {iceServers: [{urls: "stun:stun.services.mozilla.com"}], sdpSemantics:'plan-b'};
4.其他
如果Public IP无法解析,请更换stun服务器:
var servers = {iceServers: [{urls: "stun:stun.l.google.com:19302"}], sdpSemantics:'plan-b'};