WHIP/WHEP协议解析:WebRTC如何挑战RTSP/RTMP
2026/9/15 19:53:21 网站建设 项目流程

做流媒体服务的人,最近应该越来越多听到 WHIP 和 WHEP 这两个词。我第一次看到 WHIP 是在技术讨论群里,有人贴了一段 curl 命令往 WebRTC 服务器推流,当时第一反应是“WebRTC 什么时候能这么简单了”。以前要接 WebRTC 推流,信令协议各家各写一套,媒体服务商给的接口乱七八糟,想从浏览器推流到自建服务器,光 SDP 交换就得折腾大半天,更别提还要应付 NAT 穿透、DTLS 握手这些底层坑。WHIP 和 WHEP 就是冲着这个痛点来的,把 WebRTC 会话管理收敛成标准的 HTTP 接口,推流用 POST,拉流用 POST/GET,删流用 DELETE,像 REST API 一样直白。

这篇文章我会从协议层面聊到落地配置,把 WHIP/WHEP 和 RTSP、RTMP 放在一起做对比,结合我实际用 SmartMediaKit 这类媒体接入中间件的经验,聊聊什么场景真的适合换、什么场景别乱换,以及真正跑起来之后会遇到哪些坑。适合正在做直播、安防、互动应用,被 WebRTC 接入门槛折磨过的后端和流媒体开发。读完你至少能回答一个问题:新项目里,到底该不该优先考虑 WHIP/WHEP。

1. WHIP/WHEP 是什么,凭什么挑战 RTSP 和 RTMP

1.1 从协议演进说起:为什么会有 WHIP/WHEP

先简单回顾一下历史。RTMP 是 Flash 时代的老将,Adobe 在 2002 年前后推出,基于 TCP 长连接,推流和拉流都靠它,后来 Flash 死了,但 RTMP 因为 CDN 生态太成熟,至今还大量活在推流上行链路里。RTSP 更老,1998 年的 RFC 2326,后来被 RTSP 2.0(RFC 7826)更新,它本质上是“流媒体远程控制协议”,负责 PLAY、PAUSE、TEARDOWN 这些控制命令,媒体数据走 RTP/RTCP,非常适合安防摄像头、IPTV 和点播场景。

问题在于,这两个协议都不是为“浏览器原生”设计的。RTMP 需要 Flash 插件,浏览器早就放弃了;RTSP 也从来没有被浏览器直接支持过。到了 WebRTC 时代,浏览器能原生收发音视频了,但 WebRTC 有一道很高的门槛:它只定义了传输和媒体层面的标准,信令(也就是双方怎么交换 SDP、怎么交换 ICE 候选)完全自由发挥。你要么自己写一套信令服务,要么依赖某个厂商的私有协议。WHIP 和 WHEP 就是在 2020 年前后开始推动的标准,WHIP 全称 WebRTC-HTTP Ingestion Protocol,WHEP 全称 WebRTC-HTTP Egress Protocol,前者解决“往 WebRTC 服务器推流”,后者解决“从 WebRTC 服务器拉流”。

它们做的事情说起来很简单:把 WebRTC 的会话管理包装成 HTTP 请求。客户端把 SDP offer 拼到 HTTP body 里发过去,服务器回一个 201 Created,附带一个 Location 地址,这个地址就是会话资源的 URL。后续如果要更新或删除会话,就对这个 URL 发 PUT 或 DELETE。媒体数据本身还是走 WebRTC 那一套 SRTP/ICE/DTLS,也就是说,WHIP/WHEP 不是替代 WebRTC 传输,而是把“接入层”标准化了。

1.2 核心机制拆解:HTTP 语义 + WebRTC 媒体

把 WHIP/WHEP 和传统协议放在一起看,会发现它们最大的特点是把两件事解耦了:会话控制走 HTTP,媒体传输走 UDP。而 RTSP/RTMP 都是控制信道和媒体信道混在一起。RTSP 用独立的 TCP 端口(默认 554)发控制指令,媒体走 RTP 端口;RTMP 干脆就在同一条 TCP 连接里用 chunk stream 同时传控制消息和媒体数据。这种差异直接决定了它们的穿透性、安全性和部署方式。

具体到 WHIP 的一次推流流程,客户端先构造一个 SDP offer,里面带上自己的媒体描述和 ICE 候选,然后用POST /whip发给服务器,Content-Type 是application/sdp。服务器收到后,会创建 PeerConnection 并处理 offer,在信令层完成 ICE 候选交换所需的配置。处理完成后返回 201,同时在响应头里带上Location: https://.../whip/session/xxxx,这个 Location 就是会话的唯一标识。等媒体传输建立,双方开始用 SRTP 加密传输音视频。想结束推流就对这个 URL 发 DELETE。WHEP 方向类似,客户端发 GET 或 POST 到 WHEP 端点创建拉流会话,服务器返回带有 SDP answer 的 201 响应。

这里要特别强调一个细节:WHIP/WHEP 没有统一规定 TURN/STUN 的配置获取方式,实际落地时一般会把 ICE 服务器信息通过信令响应头(比如Link: rel="ice-server")或者配置接口告诉客户端。所以你看协议文档的时候,会发现它大量依赖 HTTP Link header 来传递补充信息,比如 TURN 服务器地址和凭证。刚开始接触很容易忽略这个头,导致客户端只拿到了 STUN 地址,在对称型 NAT 下连通性直接出问题。

1.3 协议对比:一张表看清差异

维度WHIP/WHEPRTSPRTMP
信令方式HTTP (POST/PUT/DELETE)RTSP 指令 (RTSP/1.0 TCP)基于 TCP 私有二进制协议
媒体传输WebRTC (SRTP over UDP)RTP/RTCP(通常 UDP)同一 TCP 连接内块传输
默认端口443/80(依赖 HTTP 服务)5541935
加密强制 DTLS-SRTP可选(通常明文)可选(RTMPE 已基本废弃)
浏览器原生支持
NAT 穿透ICE/STUN/TURN 内建难,一般靠公网 IP 或端口映射难,出网容易入网困难
延迟亚秒级,可到 200-500ms500ms 到秒级不等1-3 秒常见
回放控制弱(标准未定义)强(PAUSE/SEEK 成熟)
成熟生态新兴,但浏览器/媒体中间件支持增长快安防、IPTV 非常成熟CDN、直播推流非常成熟

从表格能直观看出,WHIP/WHEP 最突出的优势是浏览器原生支持和内建的 NAT 穿透能力。这也是它最可能改变现有选型逻辑的地方——过去 Web 端要做低延迟直播,要么走 WebSocket + MSE 自己组装,要么用 Flash 时代的 RTMP 方案转 HLS 牺牲延迟,要么接第三方厂商的私有 WebRTC 网关。现在有了统一标准,自建这条路终于好走了。

2. 选型思考:什么场景该换,什么场景不该换

2.1 更该换的场景:Web 互动、复杂网络、低延迟诉求

我自己的判断是,只要你的终端以浏览器为主,同时对延迟敏感、对网络环境不可控,WHIP/WHEP 几乎不用犹豫。典型的例子是远程协作类应用:白板共享、远程指导、在线课堂的师生视频连线。这些场景以前用 RTMP 推流到服务器再分发给观众,端到端延迟动不动 2 到 5 秒,发起一个连麦请求还要等画面从服务器绕一圈,体验很割裂。用 WHIP 做推流上行、WHEP 做播放下行,浏览器里直接用 WebRTC 原生能力,延迟能压到 500ms 以内。

还有一类场景是“终端在公网、服务端也在公网,但中间隔着复杂的 NAT”。比如外场人员用 4G/5G 手机往平台回传现场画面,手机所在网络往往是运营商级 NAT(CGNAT),传统的 RTSP 主动拉流根本拉不到。RTMP 推流勉强能用,但 TCP 在弱网下的抗丢包表现不如 WebRTC 的拥塞控制。这时候 WHIP 推流 + ICE 的候选收集,加上必要的 TURN 中继,是整个链路最稳的方案。我实际测试下来,同一段 4G 网络,RTMP 推流在丢包超过 2% 就花屏卡顿,WebRTC 的 NACK/重传机制能让画面保持流畅。

2.2 不该换的场景:存量设备、广播级、海量低成本分发

不过,WHIP/WHEP 离“全面取代”还远得很。最现实的原因是存量设备。安防行业有海量的摄像头、NVR,它们只支持 RTSP,有些甚至只支持 RTSP over UDP,去跟这些设备谈协议升级,等于让用户重新买硬件,这在项目上完全不可接受。既然设备不改,服务端就必须继续支持 RTSP 接入,然后由服务中间件把 RTSP 流转换成 WebRTC 或其他协议分发给终端。这也是我强调“中间件”很重要的原因——真正落地的架构,不是二选一,而是并存的转换层。

另外,单纯从成本角度看,海量低并发、以分发为主的直播场景,比如大型活动直播、电视台公共信号分发,WebRTC 并不比传统架构便宜。RTMP 推到 CDN,再由 CDN 切成 HLS/HTTP-FLV 分发出去,是一套非常成熟的低成本大并发链路。WebRTC 播放每个观众都建立一条独立的有状态连接,媒体服务器要维护每个连接的 ICE 状态、DTLS 会话、SRTP 密钥,单机可承载的并发远低于纯转封装分发。目前业界做 WebRTC 分发,单机千路已经算不错,而 HTTP-FLV 或 HLS 单机几万路很常见。凡是追求“便宜、量大”的场景,传统协议依然有绝对优势。

2.3 成本与复杂度评估:一张决策清单

综合来看,技术选型不是看协议新不新,而是看链路成本和收益。我建议用下面这张清单逐项过一遍:

  • 终端类型:终端全是浏览器或移动 App(原生支持 WebRTC),加分;终端是老旧摄像头、机顶盒、智能电视,减分。
  • 延迟要求:要求在 1 秒以内,比如连麦、远程控制,选 WHIP/WHEP;允许 3 秒以上,HLS 完全够。
  • 交互方向:需要双向推拉流、需要多人上行,WHIP/WHEP 优势明显;单向分发为主,传统协议更稳。
  • 网络环境:大量公网、跨运营商、NAT 复杂,选 WHIP/WHEP;内网裸光纤、专线固定 IP,RTSP 更直白。
  • 运维能力:能接受部署 STUN/TURN、处理 UDP 端口范围、监控 WebRTC 统计指标,选新协议;只能维护简单 nginx 加静态配置,别给自己找事。
  • 资金成本:小规模、高价值互动应用,用 WebRTC 值得;海量低成本分发,继续用 RTMP/HLS。

我不建议做“全量替换”式的迁移。更合理的路径是:新业务优先考虑 WHIP/WHEP,旧业务保持 RTSP/RTMP,中间用 SmartMediaKit 这类中间件做协议互转,让新旧链路共存一段时间,用数据说话。

3. SmartMediaKit 的 WHIP/WHEP 实践

3.1 SmartMediaKit 在流媒体链路中的定位

SmartMediaKit 这个名字听起来像是一个“智能媒体工具包”,在实际项目里,我更多是把它当作一个流媒体接入与分发中间件来用。它的核心价值不是某一种协议本身,而是把 RTSP、RTMP、WHIP、WHEP、HLS、HTTP-FLV 这些协议的接入、转换和分发收拢到同一套内核里。这样上层业务只面向统一的数据模型,不必关心某个流是从 RTSP 摄像头来的,还是从 WHIP 推流来的,底层协议差异由中间件消化。

在协议转换方面,典型路径有几种:

  • RTSP 摄像头 -> SmartMediaKit(RTSP 拉流)-> 转 WHIP/WHEP 分发给浏览器;
  • 浏览器 -> WHIP 推流 -> SmartMediaKit -> 转 RTMP 推到 CDN;
  • RTMP 推流(OBS)-> SmartMediaKit -> 转 WHEP 让网页端低延迟观看。

这样的设计思路,本质上是把协议当成“适配器”而不是“领域模型”。开发人员写业务代码时只需要理解一个抽象概念——“流”,流有 id、有来源、有目标格式、有状态,至于底层是哪个协议,由插件层处理。这个思路和网关模式、适配器模式完全一致,也是我建议你评估任何媒体中间件时优先看的一点:它支不支持多协议互转,而不仅仅是某个协议的新实现。

3.2 WHIP/WHEP 接入配置与关键参数

以 SmartMediaKit 为例,要开放 WHIP/WHEP 接入,核心配置项大致包括这几类(具体字段名以你实际使用的版本为准,不同项目有差异,但思路通用):

whip: enabled: true endpoint: /whip auth: type: bearer token: your-token-here ice_servers: - urls: turn:turn.example.com:3478?transport=udp username: webrtc credential: webrtc-secret - urls: stun:stun.example.com:3478 webrtc: udp_port_range: "10000:20000" candidate: "120.88.88.88" # 公网 IP,或通过 ICE 服务自动发现 dtls_cert: /etc/smartmediakit/dtls.crt dtls_key: /etc/smartmediakit/dtls.key whep: enabled: true endpoint: /whep auth: type: bearer token: your-token-here

这里几个参数值得展开说。第一是ice_servers,它决定了客户端在公网能不能连通。如果只有 STUN,那只对锥型 NAT 有效,对称型 NAT(很多企业网和 4G 网络就是)必须靠 TURN 中继。生产环境我建议至少自建一个 coturn 并配好 STUN + TURN over UDP/TCP,别省这个成本。第二是udp_port_range,WebRTC 媒体流走后端动态 UDP 端口,你需要在防火墙里放行这段范围。范围越大并发越高,但安全风险也越大,10000:20000 对中小项目够用。第三是candidate,如果服务器部署在 NAT 后面,必须指定一个公网可达的地址,否则客户端收到的候选是内网 IP,连接永远建不起来。

鉴权方面,WHIP/WHEP 标准允许通过 HTTP 层的 Bearer Token 做接入认证。在信令和媒体分离的架构里,这个设计非常方便:你可以把 token 的发放接入自己的用户体系,拿到 token 才能 POST 创建会话。不过要注意,HTTP 层鉴权只能管住信令,WebRTC 一旦建立连接,媒体流本身是端到端加密的,但服务器无法在媒体层面做按用户鉴权,所以生产上还要配合应用层业务逻辑,比如在 SDP 的媒体描述里带自定义参数,或者干脆在每个会话内部再拉一次业务接口校验。

3.3 与既有 RTSP 拉流体系(gsteamer 等)的协同

很多实际项目并不会直接以 WHIP 作为流的上游,而是先有安防平台或旧系统在跑 RTSP。比如生产环境里经常能看到rtsp://10.x.x.x/pltv/888888.xxx.smil这种格式的地址,后缀带 smil 表示是流媒体索引文件,里面描述了多码率或轨道信息。在这种场景下,SmartMediaKit 的做法是从 RTSP 地址拉流进来,解析 SDP,再以 WHIP/WHEP 向外提供服务,相当于给旧系统加了一个 WebRTC 出口。

在拉流这一侧,我遇到过几种必须处理的细节:

  • RTSP 地址可能带路径参数:比如带会话 ID、流 ID、鉴权参数,配置时不要把 URL 写死,最好支持通配符和正则模板。
  • RTSP 鉴权:很多设备用的是 Digest 认证,中间件要能完成 Digest handshake,而不是只支持 Basic。
  • RTP over TCP 开关:部分弱网环境需要 RTSP over TCP,以减少 UDP 丢包,这需要客户端在 SETUP 时主动指定TCP传输模式。
  • 按需拉流与超时回收:海量摄像头不能全部保持长连接,要有 idle 超时和自动重连机制。

另一个常见协同是用 GStreamer 快速搭一个临时 RTSP 服务器来做验证。比如开发时没有现成的摄像头,可以:

gst-launch-1.0 -v v4l2src ! videoconvert ! x264enc tune=zerolatency ! rtph264pay pt=96 name=pay0 ! rtspclientsink location=rtsp://127.0.0.1:8554/test

然后让 SmartMediaKit 从这个本地 RTSP 地址拉流,再通过 WHEP 端点分发给浏览器。这套组合在验证链路、调试信令时非常高效,不需要翻仓库找设备,也不需要跟硬件厂商要测试账号,一条命令起本地源,接着就能验证中间件的拉流、转封装、WHEP 分发整条链路。唯一要注意的是x264enc tune=zerolatency参数一定要带上,否则 GStreamer 默认的编码缓冲会给流带来不小的延迟,调试时你会误以为是协议的问题。

4. 实操过程:从 RTSP/RTMP 到 WHIP/WHEP 的落地记录

4.1 最小可用实例:部署与验证

这里我以部署一个支持 WHIP/WHEP 的媒体服务为例,讲一下从零验证的完整流程,SmartMediaKit 只是其中一个可选项,其他的 WebRTC 媒体服务器或网关也适用同样的思路。部署方式一般有 Docker 和裸机两种,开发环境我建议直接用 Docker,方便干净:

# 以 coturn 为例,先准备好 TURN/STUN docker run -d --name coturn -p 3478:3478/udp -p 3478:3478/tcp \ -p 49160-49200:49160-49200/udp \ coturn/coturn -n --log-file=stdout \ --lt-cred-mech --fingerprint \ --realm=example.com \ --user=webrtc:secret \ --min-port=49160 --max-port=49200 # 然后启动支持 WHIP/WHEP 的媒体服务容器 docker run -d --name smartmediakit \ -p 8080:8080 -p 10000-20000:10000-20000/udp \ --net=host \ your-registry/smartmediakit:latest

需要特别说明的是--net=host。在 Docker 里跑 WebRTC 服务,如果还用默认的 bridge 网络,容器内部的 UDP 端口映射和宿主机的真实 IP 映射会非常难搞,媒体服务器经常拿到错误的内网容器 IP 候选,导致客户端媒体流无法穿透。开发环境图省事,实测下来最稳的做法就是 host 网络,生产环境则建议用 Kubernetes 的 hostNetwork 或专门给媒体服务配置 underlay 网络。

启动后,用 curl 直接验证 WHIP 端点是否正常。先准备一个最简单的 SDP offer,可以用浏览器控制台从 WebRTC 页面导出,也可以手写一个仅含音频的 offer。对端点发 POST:

curl -i -X POST "http://127.0.0.1:8080/whip" \ -H "Content-Type: application/sdp" \ -H "Authorization: Bearer your-token-here" \ --data-binary @offer.sdp

如果返回 201,并且响应头里有 Location 和 Link(通常带 ice-server 的 TURN 地址),说明 WHIP 接入已经打通。接下来把 Location 里的 session id 记住,用 PUT 和 DELETE 再验证会话更新和删除:

curl -X PUT "http://127.0.0.1:8080/whip/session/xxxx" \ -H "Content-Type: application/sdp" \ --data-binary @updated-offer.sdp curl -X DELETE "http://127.0.0.1:8080/whip/session/xxxx"

这套验证能帮你确认三件事:HTTP 层路由是否正常、鉴权是否生效、会话生命周期管理是否到位。我每次部署完一个新环境,都会先跑一遍这个流程,比在浏览器里调试直观得多。

4.2 用测试地址验证推拉流

接下来是真正的视频链路验证。这里用到的技巧是,先找一个可用的测试流地址,再用 ffmpeg 做协议转换,最后用浏览器通过 WHEP 观看。测试流一般有两类:一类是网上公开的测试 RTMP 地址,这类地址我不建议依赖,稳定性不可控,而且有些带着演示业务,帧率码率都不稳定;另一类是自己用 ffmpeg 往本地起一个 RTSP 或 RTMP 服务,完全可控。

先用 ffmpeg 生成一个本地测试流,用测试图源作为视频输入:

ffmpeg -re -f lavfi -i testsrc2=size=1280x720:rate=30 \ -f lavfi -i sine=frequency=1000:sample_rate=44100 \ -c:v libx264 -preset ultrafast -tune zerolatency \ -c:a aac -shortest \ -f flv rtmp://127.0.0.1:1935/live/test

把 RTMP 推流到本机后,再通过 SmartMediaKit 转成 WHEP 分发给网页端。浏览器端播放 WHEP 流的代码没有特别多玄学,直接用 WebRTC API 拿到远端 SDP answer,然后 addTrack/ontrack 渲染到 video 标签:

const pc = new RTCPeerConnection({ iceServers: [{ urls: "stun:127.0.0.1:3478" }] }); pc.ontrack = (e) => { video.srcObject = e.streams[0]; video.play(); }; const offer = await pc.createOffer(); await pc.setLocalDescription(offer); const res = await fetch("http://127.0.0.1:8080/whep", { method: "POST", headers: { "Content-Type": "application/sdp" }, body: offer.sdp, }); const answer = await res.text(); await pc.setRemoteDescription({ type: "answer", sdp: answer });

这里有一个容易踩的坑:WHEP 请求体和 WHIP 一样也是application/sdp,服务端返回的也是纯 SDP,而不是 JSON。很多人习惯性用 JSON 封装,结果格式不符,信令一直失败。我用浏览器原生 WebRTC 调试时第一次就犯了这错误。

如果觉得手写 SDP 太麻烦,也可以直接用 ffmpeg 测试 WHIP 推流能力,前提是 ffmpeg 版本构建时开启了 WebRTC 支持。不过说实话,ffmpeg 的 WHIP 支持目前还不如 RTSP/RTMP 成熟,生产环境我主要还是靠浏览器原生的方式推流播放。

4.3 迁移步骤与回退方案:一个可复用的套路

从 RTSP/RTMP 迁移到 WHIP/WHEP,我推荐按下面四个阶段走:

  1. 旁路验证:服务中间件同时保留旧协议和新协议入口,把一小部分测试流量通过 WHIP/WHEP 走一遍,对比延迟、卡顿、首帧时间。这一阶段不改动任何生产设备和网络架构。
  2. 新业务上线用新协议:新开发的 Web 端、移动端功能全部走 WHIP/WHEP;旧的桌面客户端、嵌入式设备保持 RTSP/RTMP。
  3. 双跑与灰度:在重要链路同时跑新旧两条路径,用数据对比稳定性和延迟。我在实际项目中通常会让两条链路并行 2 到 4 周,重点看 WebRTC 链路在高峰期 UDP 丢包和重传情况。
  4. 旧链路逐步下线:当旧链路的流量降到个位数、且业务方确认新链路稳定后,才考虑下线旧协议入口。但要注意,下线前要留一个配置开关,万一新链路出问题,可以一键切回。

回滚方案这点太重要了,很多团队迁移失败都是因为把新旧链路割裂开,没有保留逃生通道。我见过一个项目,迁移 WebRTC 播放链路后,因为一套老旧防火墙规则没更新,UDP 包丢了将近 30%,画面频繁花屏,最后因为没有回滚开关,整个团队半夜加班修。所以我的原则是:新协议永远和旧协议并行存在直到你信心十足,回滚永远是一行配置的事,而不是重新部署一套系统。

5. 常见问题与排查技巧实录

5.1 典型问题速查表

把我在实践中遇到的高频问题整理成一张表,方便你对照:

问题现象可能原因排查方向
浏览器播放黑屏,但 SDP 协商成功编解码不支持(如服务端只给 H.264 但浏览器只解 VP8/VP9)检查 SDP 中媒体编解码类型,统一转码或协商
WHIP 推流后对端一直 no audio/video浏览器没有 getUserMedia 授权,或采集失败打开浏览器权限设置,检查控制台初始化错误
ICE 连接一直 checking,最终 failed候选地址不对、STUN/TURN 未配置抓包看 ICE 候选,检查 TURN 是否可达
公网播放卡顿严重UDP 端口范围未放行,或 NAT 穿透走了性能较差的路径检查防火墙 UDP 范围,确认候选是否走了 TURN
WebRTC 连接几秒后断开会话超时、NAT 映射过期、心跳未正确处理检查服务端会话生命周期配置,客户端是否持续发送 STUN binding
服务端 CPU 高企DTLS 握手频繁、并发连接数过大检查是否每帧都新建 PeerConnection,连接复用是否生效
部分浏览器能播,部分不能浏览器能力差异,或移动端后台限制 WebRTC用 webrtc-internals 对比正常和异常浏览器的候选和码率统计

5.2 排查思路:从信令到媒体链路

WHIP/WHEP 问题排查,我习惯分成三段:信令层、传输层、媒体层。信令层主要看 HTTP 交互是否正常。浏览器打开chrome://webrtc-internals,能看到完整的信令记录和 ICE 候选收集情况。如果候选收集里没有公网 IP,那基本可以确定 STUN 没配好;如果候选了公网 IP 但连接还失败,大概率是 UDP 被防火墙拦了。

传输层用 tcpdump 或 Wireshark 抓包,过滤条件建议用udp port 3478 or udp portrange 10000-20000。抓到 STUN 包就能看到 binding request/response,如果只有 request 没有 response,说明对端不可达。SRTP 包能看到包头的 payload type,如果全是 RTP 重传包,说明网络丢包严重。我一般会看三个统计指标:丢包率、抖动、RTT。WebRTC 的 rtcStats API 或 webrtc-internals 里都有,当丢包率超过 3% 开始出现可感知的卡顿,超过 5% 基本体验不可接受,需要检查网络或启用 TURN 中继的更好链路。

媒体层的问题就比较杂了,最容易遇到的是编解码协商不一致。WebRTC 虽然强制支持 VP8,但很多 IP Camera 或转码模块只出 H.264,两者要打通必须转码。另外 Safari 对 H.264 支持较好但对 VP9 支持不一,如果你的用户分布广,直接在服务端统一转 H.264 是最省心的方案。

5.3 我踩过的坑:三个防不胜防的细节

最后分享几个我实际踩过、且文档里很少写清楚的坑。

第一个是大坑:内网测试时用了 mDNS 候选,导致外网全部连不上。浏览器在局域网内会自动收集 mDNS 候选,形如xxx.local,这类候选只在内网有效。如果服务端返回的候选直接用这种 mDNS 地址,外网客户端根本无法解析。解决方法是在服务端配置一个明确的可路由候选地址,或者在客户端通过 ICE 服务器策略禁止 mDNS。

第二个坑:对称型 NAT 下没配 TURN,媒体流全挂。公司内部网络、部分 4G 网络是对称型 NAT,STUN 只能拿到映射后的公网地址,但无法建立直接连接,必须走 TURN 中继。很多项目上线前只用办公室网络测试,觉得 P2P 效果好,一到用户真实验证就傻眼。我的建议是一开始就部署好 coturn,并且把 TURN over TCP 也开起来,因为有些企业防火墙连 UDP 3478 都拦。

第三个坑和协议无关,但特别容易炸:浏览器页面里 WebRTC 连接没有正确清理,导致服务器连接数暴涨。单页应用如果只创建 PeerConnection 不主动 close,在弱网环境下反复重连,服务端会堆一堆僵尸连接。排查时看会话数远远大于活跃用户数就要警惕。解决办法是在页面路由切换或组件卸载时主动pc.close(),同时服务端设置合理的 idle 超时。

这些小细节单独拎出来都不起眼,但组合在一起就是线上事故。协议再标准,落地时还是离不开对底层传输机制的理解。我个人体会是,从 RTSP/RTMP 迁移到 WHIP/WHEP,技术门槛其实没有想象中高,真正的门槛在于对 WebRTC 传输特性的熟悉程度和对网络环境的敬畏。如果你正在设计新系统,不妨把 WHIP 推流 + WHEP 拉流作为优先选项,同时保留传统协议的接入能力,让中间件帮你兜底,这样既跟上了趋势,又不会把自己逼到没有退路的角落。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询