WebRTC连接仅发送一个ICE候选 代码问题排查求助
问题分析与修复方案
你代码中存在的几个直接导致仅发送单个ICE候选的问题如下:
- 重复调用
createOffer:你在createPeerConnection函数内同步执行了一次无返回处理的peerConnection.createOffer(offerOptions),后续又在异步函数createAndSendOffer中再次调用该方法,重复的Offer生成逻辑会打乱WebRTC的ICE候选收集流程,iPhone端的Safari浏览器对这类异常调用的容错性比Chrome更低。 - 事件监听时机错误:你先触发了
createAndSendOffer执行SDP协商流程,之后才绑定onicecandidate事件监听。WebRTC在调用setLocalDescription后会立刻开始ICE候选收集,很可能前几个候选触发事件时,你还没有绑定对应的监听函数,导致候选漏发。 - ICE服务器配置为空:你当前
iceServers参数是空数组,没有配置STUN/TURN服务器,仅能收集到同一局域网下的本地host候选,通常这类候选只有1-2个,如果跨网段的话甚至不会收集到可用候选,iPhone Safari在无ICE服务器配置时会提前终止候选收集流程。
修复后的代码
const createPeerConnection = async (signaling) => { const peerConnection = new RTCPeerConnection({ // 配置可用的STUN服务器,可替换为自搭建的STUN/TURN服务 iceServers: [ { urls: 'stun:stun.l.google.com:19302' } ], }); const offerOptions = { offerToReceiveVideo: true, offerToReceiveAudio: true }; // 先绑定所有事件监听,再执行SDP相关操作 peerConnection.onicecandidate = (iceEvent) => { if (iceEvent && iceEvent.candidate) { signaling.send(JSON.stringify({ type: MESSAGE_TYPE.IceCandidate, payload: iceEvent.candidate, })); } // iceEvent.candidate为null时代表ICE收集完成,无需额外处理 }; peerConnection.onconnectionstatechange = (state ) => { console.log(peerConnection.connectionState); }; // 移除多余的同步createOffer调用,统一走异步流程 await createAndSendOffer(signaling, peerConnection, offerOptions); return peerConnection; }; const createAndSendOffer = async (signaling, peerConnection, offerOptions) => { const offer = await peerConnection.createOffer(offerOptions); await peerConnection.setLocalDescription(offer); signaling.send(JSON.stringify({ type: MESSAGE_TYPE.SessionDescription, payload: offer })); };
额外注意事项
- 如果需要跨公网连接,必须额外配置TURN服务器,仅靠STUN服务器无法处理对称网络环境下的打洞需求
- iPhone Safari要求WebRTC相关页面必须运行在HTTPS环境下(localhost本地调试除外),否则会直接禁止媒体和PeerConnection相关接口调用
- 建议对
signaling.send方法做异常捕获,避免信令发送失败导致候选丢失
内容的提问来源于stack exchange,提问作者Juan Gil
相关产品推荐
相关产品推荐

