You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WebRTC的RTCPeerConnection状态一直停留在new不变化,该如何排查?

WebRTC连接失败问题排查与修复

核心问题

  • 缺失传输载体绑定:RTCPeerConnection 必须绑定至少一个音视频轨或者DataChannel数据通道,才会触发后续的连接建立流程,无传输内容时连接会一直停留在new状态。
  • 未实现ICE候选交换逻辑:SDP交换仅完成媒体能力协商,还需要交换双方的网络地址、端口等ICE候选信息才能建立实际的网络连接,当前代码完全没有处理候选收集和交换逻辑。
  • 服务端PeerConnection实例生命周期错误:服务端每次收到/testing请求都新建RTCPeerConnection实例,且未存储实例,后续的ICE候选交互找不到对应的连接对象,无法完成协商。
  • 客户端变量作用域隐患:如果pc变量未做持久化存储,异步逻辑执行完毕后可能被垃圾回收,导致定时器访问的实例异常。

修复方案

客户端代码修改

import React from 'react'
import axios from 'axios'

function App() {
  // 用useRef持久化存储pc实例,避免被回收
  const pcRef = React.useRef(null)

  React.useEffect(() => {
    pcRef.current = new RTCPeerConnection()
    // 1. 创建DataChannel,触发连接建立流程
    pcRef.current.createDataChannel('test-channel')

    // 2. 监听本地ICE候选,收集后上报服务端
    pcRef.current.onicecandidate = (e) => {
      if (e.candidate) {
        axios.post('http://localhost:3000/ice', { candidate: e.candidate })
      }
    }

    (async () => {
      const offer = await pcRef.current.createOffer()
      await pcRef.current.setLocalDescription(offer)
      const { data } = await axios.post('http://localhost:3000/testing', {
        sdp: pcRef.current.localDescription
      })
      await pcRef.current.setRemoteDescription(data.sdp)
      // 3. 添加服务端返回的ICE候选
      data.candidates.forEach(cand => pcRef.current.addIceCandidate(cand))
    })()

    const timer = setInterval(() => {
      if (pcRef.current) {
        console.log(pcRef.current.connectionState)
      }
    }, 2222)

    // 组件卸载时清理定时器
    return () => clearInterval(timer)
  }, [])

  return <div>WebRTC测试</div>
}

服务端代码修改

const webrtc = require('wrtc')
// 测试用全局存储pc实例和候选,生产环境请按用户标识关联存储
let pc = null
let pendingCandidates = []

server.post('/testing', async function (req, res) {
  const { sdp } = req.body
  pc = new webrtc.RTCPeerConnection()
  
  // 监听客户端创建的数据通道
  pc.ondatachannel = (e) => {
    console.log('数据通道建立成功', e.channel)
  }

  // 收集服务端ICE候选
  pc.onicecandidate = (e) => {
    if (e.candidate) {
      pendingCandidates.push(e.candidate)
    }
  }

  await pc.setRemoteDescription(sdp)
  const answer = await pc.createAnswer()
  await pc.setLocalDescription(answer)
  
  // 返回answer和暂存的服务端候选
  res.status(200).json({
    sdp: pc.localDescription,
    candidates: pendingCandidates
  })
  pendingCandidates = []
})

// 新增接口接收客户端ICE候选
server.post('/ice', async function (req, res) {
  const { candidate } = req.body
  if (pc && candidate) {
    await pc.addIceCandidate(new webrtc.RTCIceCandidate(candidate))
  }
  res.sendStatus(200)
})

本地测试无需额外配置STUN/TURN服务器,修改完成后即可正常看到连接状态变为connected。

内容的提问来源于stack exchange,提问作者Hypothesis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 16:57:03