拓冰建站拓冰建站
首页 / 资讯中心 / 正文

直连建不起来、通话频繁掉线?用 Cloudflare TURN 补齐 8 个生产级坑点的实战指南

直连建不起来、通话频繁掉线用 Cloudflare TURN 补齐 8 个生产级坑点的实战指南【免费下载链接】skillsSkills Catalog for Codex项目地址: https://gitcode.com/GitHub_Trending/skills4/skillsWebRTC 直连被 NAT 挡住的场景用 Cloudflare TURN 做中继兜底。本文从凭证签发与刷新、TURN 端口选择、ICE 重启到 WebRTC 掉线排查补齐 8 个生产级坑点帮你把通话打通并长期稳住。为什么直连会失败NAT 与防火墙怎么卡住 P2P先说一个很真实的场景两个用户都开着通话页面本机自测一切正常可一到真实网络RTCPeerConnection就卡在checking上iceconnectionstatechange迟迟不走到connected。八成不是你代码写错了是网络在作怪对称 NAT每次发出去都换一个不同的内网端口对端的回应根本回不来企业防火墙把 WebRTC 常用口3478、5349、443拦了或只放行 HTTPS 出站运营商级 NATCGNAT手机网络尤其典型一大群人共用一个出口 IPP2P 基本无望。这类环境里P2P 直连要么建不起来要么建起来也脆。解法就是让流量改走一台中立的中继。Cloudflare TURN 跑在它全球 anycast 网络上客户端就近接入、无需手动选区选点正是为这种直连必挂的场景兜底。经验法则直连优先、中继兜底。绝大多数场景你不想让全部流量都绕远路只在直连失败时才落到 TURN——延迟和成本都最划算。一张图看懂 STUN 与 TURN 的分工把 STUN 和 TURN 的职责拆清楚你才知道为什么两个都要塞给浏览器两者同时放进iceServers数组交给RTCPeerConnection后面的择优完全交给 ICE 协商STUN 负责把客户端藏在 NAT 后的公网地址照出来让双方先尝试直连一旦某个网络环境直连走不通ICE 就自动回落到 TURN 中继流量经turn.cloudflare.com转发。你不需要自己判断该不该走中继把两个都交给浏览器即可。三分钟跑通最小可用接入三步就能拉起一个能用的接入顺序很关键先在后端备好凭证再让前端来取。步骤在哪做干什么1. 创建 TURN KeyCloudflare APIPOST /accounts/{account_id}/calls/turn_keys拿uid和key密钥只在创建时返回一次立刻存好2. Worker 签发临时凭证你的 Worker收到请求后带密钥调凭证生成端点过滤 53 后把username/credential返回3. 客户端组装 iceServers浏览器拉取你的接口拼上 STUN TURN交给RTCPeerConnection前端组装iceServers的最小片段async function getIceServers() { const { username, credential } await fetch(/api/turn-credentials).then(r r.json()); return [ { urls: stun:stun.cloudflare.com:3478 }, { urls: [turn:turn.cloudflare.com:3478?transportudp, turn:turn.cloudflare.com:3478?transporttcp, turns:turn.cloudflare.com:5349?transporttcp, turns:turn.cloudflare.com:443?transporttcp], username, credential, credentialType: password } ]; } new RTCPeerConnection({ iceServers: await getIceServers() });三个要点username/credential一定来自你的后端浏览器自己拿不到密钥STUN 那行永远叠加一个公开服务器保证发现公网候选这条链路始终在TURN 的urls放多个传输方式udp / tcp / tls让 ICE 自己挑能通的那个。TURN 端口怎么选一张表看懂取舍浏览器端推荐的尝试顺序本质是延迟优先、可靠性兜底优先级端口 / 传输适用网络13478/udp首选延迟最低23478/tcpUDP 被封时的回退35349/tls企业防火墙场景最稳4443/tls备用 TLS 口防火墙友好必须记住端口 53 在浏览器里必须过滤而且过滤要放在服务端。Chrome 和 Firefox 会静默拦截 53 端口的流量——它不报错只是无声无息地连不上排查起来最磨人。凭证生成接口的响应里天然就带着turn:turn.cloudflare.com:53?transportudp这类地址所以别指望前端兜底在你自己的 Worker 里先滤掉、再排好序function toBrowserUrls(urls: string[]): string[] { return urls .filter(u !u.includes(:53)) // 浏览器拦 53服务端先滤掉 .sort((a, b) { if (a.includes(transportudp)) return -1; if (b.includes(transportudp)) return 1; if (a.includes(transporttcp) !a.startsWith(turns:)) return -1; if (b.includes(transporttcp) !b.startsWith(turns:)) return 1; return 0; }); }为什么在服务端滤因为响应里的 53 地址对非浏览器客户端原生 App是可用的只在浏览器里是废的。服务端统一过滤前端零心智负担也避免旧客户端把 53 又透传出去。TURN 凭证刷新怎么做才不会掉线凭证是临时的这是最大的隐藏坑。TTL 上限 48 小时172800 秒超过 API 直接拒单。长通话一定要在到期前续上刷新时机以ttl * 1000 - 60000提前 1 分钟作为刷新间隔别卡在到期那一秒续用要配合setConfiguration()它只更新iceServers不会触发 ICE 重启真掉线了还得配合restartIce()。服务端的凭证缓存一个TURNCredentialsManager大致这么做内存里存一份{ username, credential, urls, expiresAt }命中且未过期直接返回省得每个客户端都去打生成端点写缓存时就把 53 过滤掉一次搞定expiresAt now ttl*1000 - 60000给刷新留窗口顺手做一道ttl 172800的防御性校验和 API 侧约束对齐。缓存有效期比真实 TTL提前 1 分钟是这套模式最容易漏掉的一行——漏了就会出现缓存里看着是好的、实际已过期的边界掉线。掉线自救四步网络切换、TURN 维护、凭证过期之后iceConnectionState会掉进failed。生产代码里别只console.log一下就躺平按这四步恢复pc.addEventListener(iceconnectionstatechange, async () { if (pc.iceConnectionState failed || pc.iceConnectionState disconnected) { await refreshTURNCredentials(pc); // 1. 刷新凭证 pc.restartIce(); // 2. 触发 ICE 重启 const offer await pc.createOffer({ iceRestart: true }); // 3. 重启型 offer await pc.setLocalDescription(offer); await sendToPeer(offer); // 4. 经信令发给对方 } });需要触发 ICE 重启的四类场景一个都不能少TURN 服务器维护Cloudflare 网络上偶发网络拓扑变化anycast 路由调整长会话 1 小时中的凭证刷新连接失败iceConnectionState failed。更稳的做法是把failed和disconnected都纳入恢复条件——移动网络切换时往往先到disconnected只盯failed会漏掉一大波掉线。高频翻车清单错误做法正确做法ttl: 6048007 天改ttl: 8640024h超 48h 直接被 API 拒硬编码turn:141.101.90.1:3478用域名turn:turn.cloudflare.com:3478IP 变更有 14 天通知期浏览器端保留:53的 URL服务端filter(!u.includes(:53))凭证到期不刷新setInterval提前 1 分钟刷新掉线只打日志failed/disconnected时刷新凭证 restartIce()把TURN_KEY_SECRET下放客户端只在服务端签发客户端请求/api/turn-credentials限额、成本与安全底线单分配限额按用户分配不是账户级维度限额超限后果唯一 IP 5 个新 IP/秒丢包包速率5–10k pps入/出丢包数据速率50–100 Mbps入/出丢包成本与 Cloudflare Calls SFU 搭配使用时 TURN免费单独用则按$0.05/GB 出站计费。想省钱优先走直连优先少让流量绕中继。安全清单上线前逐项过一遍凭证只在服务端生成绝不下发密钥TURN_KEY_SECRET进 wrangler secrets不进varsTTL ≤ 预期会话时长且 ≤ 48 小时凭证生成端点做限流签发前先做客户端认证为被攻陷的会话提供凭证吊销/credentials/revoke返回 204计费立即停不硬编码 IP或建立 DNS 监控浏览器客户端过滤 53 端口。什么时候该把流量交给 SFU按业务对连通性和效率的取舍用两个策略开关控制 ICE 行为场景配置理由视频会议iceTransportPolicy: all先试 P2P 直连失败才走中继省成本IoT / 可预测连通iceTransportPolicy: relay强制全走 TURN连通性可预期屏幕共享bundlePolicy: max-bundle多路媒体聚合到一条传输降开销如果直接用 Cloudflare Calls SFUTURN 会在需要时自动启用客户端不用自己编排TURN SFU的协调——建个 session 就行。几个容易忽略的部署边界IPv6客户端到 TURN 支持 IPv4/IPv6但中继地址只分配 IPv4不支持 RFC 6156TCP 中继RFC 6062也不支持——IPv6 客户端能接入中继流量仍走 IPv4TLS1.1 / 1.2 / 1.3 都支持。TLS 1.3 推荐AEAD-AES128-GCM-SHA256、AEAD-AES256-GCM-SHA384、AEAD-CHACHA20-POLY1305-SHA256TLS 1.2 推荐ECDHE-ECDSA-AES128-GCM-SHA256、ECDHE-RSA-AES128-GCM-SHA256。进一步阅读仓库里的完整参考相对仓库根目录服务概览与端口清单references/turn/README.md凭证生成/吊销、Key 管理、类型与 TTL 约束references/turn/api.mdWorker 搭建、wrangler.jsonc、环境变量、IP 白名单references/turn/configuration.md实现模式与用例references/turn/patterns.md常见错误、限额、安全与排障references/turn/gotchas.md【免费下载链接】skillsSkills Catalog for Codex项目地址: https://gitcode.com/GitHub_Trending/skills4/skills创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门