2、环境搭建:浏览器兼容性检查、本地开发环境配置(Node.js、HTTPS证书)、第一个WebRTC Demo

好,咱们正式开始动手了。

这一章说白了就是「把枪擦亮」。环境搭不好,后面全是坑。我见过太多人卡在第一步——不是浏览器不支持,就是本地跑不起来,最后连个摄像头都打不开。嗯,咱们今天就把这事彻底搞定。

2.1 浏览器兼容性:别让浏览器拖后腿

WebRTC 虽然已经是个成熟技术,但不同浏览器的支持程度还是有差异的。我个人习惯,开发时首选 Chrome 或 Edge,调试工具最顺手。

先看看你的浏览器行不行。打开这个页面:

// 最简单的兼容性检测
const checkWebRTC = () => {
  const result = {
    getUserMedia: !!navigator.mediaDevices?.getUserMedia,
    RTCPeerConnection: !!window.RTCPeerConnection || !!window.webkitRTCPeerConnection,
    RTCDataChannel: !!window.RTCPeerConnection
  };
  
  console.table(result);
  
  if (result.getUserMedia && result.RTCPeerConnection) {
    console.log('✅ 你的浏览器支持 WebRTC');
  } else {
    console.error('❌ 浏览器不支持 WebRTC,请升级到最新版 Chrome 或 Edge');
  }
};

checkWebRTC();

这段代码会输出三个关键能力:摄像头/麦克风访问、点对点连接、数据通道。三个都是 true,恭喜你,可以继续了。

💡 我的经验: 曾经有个项目在 Chrome 上跑得好好的,换到 Safari 就黑屏。后来发现是 Safari 对 getUserMedia 的约束参数要求更严格。所以开发时最好多浏览器测一遍。

2.2 Node.js 环境:你的本地服务器

WebRTC 需要信令服务器来交换连接信息。虽然咱们第一个 Demo 可以纯前端跑,但后面肯定要上 Node.js。先把环境配好。

nodejs.org 下载 LTS 版本。安装完验证一下:

node -v   # 我目前用的是 v18.16.0
npm -v    # 9.5.1

然后创建一个项目目录:

mkdir webrtc-demo
cd webrtc-demo
npm init -y

这会生成一个 package.json。我个人习惯把端口号、域名这些配置单独放一个 .env 文件,但今天咱们先简单点。

2.3 HTTPS 证书:WebRTC 的硬门槛

这里有个重要的事:WebRTC 的 getUserMedia 只能在安全上下文(HTTPS 或 localhost)下使用

为什么?因为浏览器不想让随便一个 HTTP 网站就能偷开你的摄像头。这个设计很合理,但给本地开发带来了一点麻烦。

解决方案有两种:

方案 适用场景 操作复杂度
localhost 纯本地开发 ⭐ 最简单
自签名证书 需要局域网测试(手机访问) ⭐⭐ 中等
mkcert 工具 本地 HTTPS 最佳实践 ⭐⭐ 推荐

我推荐用 mkcert,它能让本地证书被系统信任,浏览器不会报红锁。安装方式:

# macOS
brew install mkcert
mkcert -install

# Windows (用管理员 PowerShell)
choco install mkcert
mkcert -install

然后在项目目录生成证书:

mkcert localhost 127.0.0.1 ::1

# 会生成两个文件:
# localhost+2.pem  (证书)
# localhost+2-key.pem  (私钥)
⚠️ 避坑指南: 我曾经在 Windows 上忘了用管理员权限运行 mkcert -install,结果证书没装进信任根目录,Chrome 一直报 NET::ERR_CERT_AUTHORITY_INVALID。折腾了半小时才发现。记住:一定要以管理员身份运行!

2.4 第一个 WebRTC Demo:打开你的摄像头

好了,环境齐了。咱们写一个最简单的 Demo——打开摄像头并显示在页面上。

先创建一个 index.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>我的第一个 WebRTC Demo</title>
  <style>
    body { font-family: system-ui, sans-serif; max-width: 600px; margin: 40px auto; padding: 0 20px; }
    video { width: 100%; border-radius: 12px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); }
    button { padding: 10px 24px; font-size: 16px; border: none; border-radius: 8px; cursor: pointer; margin: 8px 4px; }
    .btn-start { background: #4CAF50; color: white; }
    .btn-stop { background: #f44336; color: white; }
    .status { margin: 12px 0; padding: 8px 16px; background: #f0f8ff; border-radius: 8px; }
  </style>
</head>
<body>
  <h2>📷 摄像头测试</h2>
  <div class="status" id="status">点击「开始」打开摄像头</div>
  <video id="localVideo" autoplay playsinline muted></video>
  <div>
    <button class="btn-start" id="startBtn">开始</button>
    <button class="btn-stop" id="stopBtn">停止</button>
  </div>

  <script>
    let localStream = null;
    const video = document.getElementById('localVideo');
    const status = document.getElementById('status');

    document.getElementById('startBtn').addEventListener('click', async () => {
      try {
        status.textContent = '⏳ 正在请求摄像头权限...';
        localStream = await navigator.mediaDevices.getUserMedia({
          video: true,
          audio: true
        });
        video.srcObject = localStream;
        status.textContent = '✅ 摄像头已打开';
      } catch (err) {
        status.textContent = '❌ 打开失败: ' + err.message;
        console.error('getUserMedia error:', err);
      }
    });

    document.getElementById('stopBtn').addEventListener('click', () => {
      if (localStream) {
        localStream.getTracks().forEach(track => track.stop());
        video.srcObject = null;
        localStream = null;
        status.textContent = '🛑 摄像头已关闭';
      }
    });
  </script>
</body>
</html>

然后启动一个 HTTPS 服务器。用 Node.js 的 https 模块:

// server.js
const https = require('https');
const fs = require('fs');
const path = require('path');

const options = {
  key: fs.readFileSync(path.join(__dirname, 'localhost+2-key.pem')),
  cert: fs.readFileSync(path.join(__dirname, 'localhost+2.pem'))
};

https.createServer(options, (req, res) => {
  const filePath = path.join(__dirname, 'index.html');
  const content = fs.readFileSync(filePath, 'utf-8');
  res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
  res.end(content);
}).listen(3000, () => {
  console.log('🔒 HTTPS 服务器已启动: https://localhost:3000');
});

运行:

node server.js

打开浏览器访问 https://localhost:3000,点击「开始」按钮。浏览器会弹出摄像头权限请求——允许它。然后你就能在页面上看到自己的脸了。

🎯 核心知识点:
  • navigator.mediaDevices.getUserMedia() 是 WebRTC 的入口,获取本地媒体流
  • 返回的 MediaStream 对象可以赋值给 video.srcObject 直接渲染
  • 每个轨道(Track)可以单独控制启停
  • 必须在 HTTPS 或 localhost 下才能使用

2.5 本章知识体系

下面这张图帮你理清今天搭的环境和它们之间的关系:

WebRTC 开发环境全景图 🌐 浏览器 Chrome / Edge / Firefox 🖥️ Node.js 服务器 信令 / 静态文件服务 🔒 HTTPS 证书 mkcert 自签名证书 📡 WebRTC 核心 API getUserMedia | RTCPeerConnection | RTCDataChannel 🎬 第一个 Demo:摄像头画面 video 标签渲染 MediaStream 环境搭建 → API 调用 → 媒体流展示

从这张图可以看得很清楚:浏览器通过 HTTPS 访问本地 Node.js 服务器,服务器提供页面,页面调用 WebRTC API,最终在页面上展示摄像头画面。每一步都环环相扣。

📌 我的建议: 第一次跑通这个 Demo 后,你可以试着改改 getUserMedia 的参数。比如把 video: true 改成 video: { width: 1280, height: 720 },看看画面清晰度的变化。或者把 audio: true 去掉,只开摄像头。多动手试试,印象更深。

好了,环境搭好了,第一个 Demo 也跑起来了。你已经在本地拥有了一个完整的 WebRTC 开发环境。接下来就可以往里面加更多东西了——比如点对点通话、屏幕共享、数据通道传输文件……

公众号:蓝海资料掘金营,微信 deep3321