第二章 浏览器兼容性与环境搭建:别让环境卡住你的第一个Demo

说实话,我见过太多人兴致勃勃想玩WebRTC,结果卡在环境搭建这一步。明明代码写得没问题,浏览器就是不给面子。今天咱们就把这事彻底捋清楚。

2.1 主流浏览器对WebRTC的支持情况

WebRTC这玩意儿,现在主流浏览器基本都支持了。但支持归支持,细节上还是有差异的。我整理了一张表,你一看就明白。

浏览器 WebRTC支持版本 核心API前缀 备注
Chrome 28+ webkit 最稳定,推荐开发首选
Firefox 22+ moz 早期有前缀,现在基本统一
Safari 11+ webkit iOS上必须用webkit前缀
Edge 12+(Chromium版79+) 无(Chromium版) 旧版Edge已死,不用管
Opera 20+ webkit 跟Chrome内核一样

嗯,这里要注意:Chrome和Safari虽然都用webkit前缀,但实现细节不完全一样。我在项目中遇到过Safari上getUserMedia返回的音频轨道格式跟Chrome不同,导致后续编码出问题。所以别偷懒,每个浏览器都得测。

2.2 getUserMedia API的兼容性处理

getUserMedia是WebRTC的入口,也是坑最多的地方。说白了,就是浏览器厂商各自为政的那段历史遗留问题。

核心问题:不同浏览器对getUserMedia的调用方式不同,有的用navigator.getUserMedia,有的用navigator.webkitGetUserMedia,还有的用navigator.mozGetUserMedia。

怎么解决?我习惯写一个适配函数,一次性搞定所有情况。

// 兼容性适配函数
function getGetUserMedia() {
  // 标准API
  if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
    return navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);
  }
  
  // 老式前缀API
  const getUserMedia = navigator.getUserMedia ||
                       navigator.webkitGetUserMedia ||
                       navigator.mozGetUserMedia ||
                       navigator.msGetUserMedia;
  
  if (getUserMedia) {
    // 包装成Promise风格
    return function(constraints) {
      return new Promise(function(resolve, reject) {
        getUserMedia.call(navigator, constraints, resolve, reject);
      });
    };
  }
  
  // 都不支持,抛出错误
  return function() {
    return Promise.reject(new Error('浏览器不支持getUserMedia'));
  };
}

// 使用示例
const myGetUserMedia = getGetUserMedia();

myGetUserMedia({ video: true, audio: true })
  .then(function(stream) {
    console.log('获取到媒体流:', stream);
  })
  .catch(function(err) {
    console.error('获取失败:', err);
  });

个人经验:我建议你直接用navigator.mediaDevices.getUserMedia这个标准API,然后加一个polyfill兜底。因为从2018年以后,主流浏览器都支持标准API了。老式前缀API主要是为了兼容那些万年不更新的浏览器。

你想想看,如果用户还在用Chrome 27这种古董,那咱们也没必要伺候了,对吧?直接提示升级浏览器就行。

2.3 搭建本地HTTPS开发环境

这是个大坑。WebRTC要求页面必须在HTTPS环境下运行,或者localhost也行。为什么?因为getUserMedia涉及摄像头和麦克风权限,浏览器不允许在非安全环境下调用。

警告:千万别想着用HTTP直接开发WebRTC!浏览器会直接拒绝getUserMedia请求,连错误提示都不给。我曾经因为这个排查了半天,最后发现是协议问题。

搭建本地HTTPS环境,我推荐两种方式:

方式一:使用mkcert(推荐)

mkcert是一个小工具,能一键生成受信任的本地证书。我个人最喜欢这种方式,因为浏览器不会报不安全。

# 1. 安装mkcert
# macOS
brew install mkcert

# Windows (用choco)
choco install mkcert

# Linux
sudo apt install libnss3-tools
wget https://github.com/FiloSottile/mkcert/releases/latest/download/mkcert-v1.4.4-linux-amd64
chmod +x mkcert-v1.4.4-linux-amd64
sudo mv mkcert-v1.4.4-linux-amd64 /usr/local/bin/mkcert

# 2. 初始化本地CA
mkcert -install

# 3. 生成证书(替换成你的域名或IP)
mkcert localhost 127.0.0.1 ::1

# 4. 启动HTTPS服务器(用Node.js举例)
const https = require('https');
const fs = require('fs');
const express = require('express');

const app = express();
app.use(express.static('public'));

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

https.createServer(options, app).listen(443, () => {
  console.log('HTTPS服务器已启动: https://localhost');
});

方式二:使用http-server + 自签名证书

如果你不想装mkcert,也可以用Node.js的http-server配合自签名证书。不过浏览器会提示不安全,需要手动信任。

# 1. 安装http-server
npm install -g http-server

# 2. 生成自签名证书(用openssl)
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes

# 3. 启动HTTPS服务器
http-server -S -C cert.pem -K key.pem -p 443

小技巧:如果你只是本地测试,直接用localhost就行,不需要HTTPS。但一旦涉及摄像头权限,必须用HTTPS。我习惯在开发时用localhost,部署时再切HTTPS。

2.4 浏览器兼容性检测工具

写代码之前,先检测一下当前浏览器是否支持WebRTC。我写了一个检测函数,你可以直接拿去用。

function checkWebRTCSupport() {
  const result = {
    supported: false,
    details: {}
  };
  
  // 检测getUserMedia
  result.details.getUserMedia = !!(navigator.mediaDevices && 
                                    navigator.mediaDevices.getUserMedia);
  
  // 检测RTCPeerConnection
  result.details.RTCPeerConnection = !!(window.RTCPeerConnection || 
                                         window.webkitRTCPeerConnection || 
                                         window.mozRTCPeerConnection);
  
  // 检测RTCDataChannel
  result.details.RTCDataChannel = !!(window.RTCDataChannel || 
                                      window.webkitRTCDataChannel);
  
  // 综合判断
  result.supported = result.details.getUserMedia && 
                     result.details.RTCPeerConnection;
  
  return result;
}

// 使用
const support = checkWebRTCSupport();
console.log('WebRTC支持情况:', support);

if (!support.supported) {
  alert('您的浏览器不支持WebRTC,请升级到最新版Chrome或Firefox');
}

嗯,这里要注意:检测结果只是参考,实际运行中可能因为权限问题导致失败。比如用户拒绝了摄像头权限,getUserMedia就会报错。所以代码里一定要加错误处理。

2.5 本章知识体系

我把这章的核心逻辑画了张图,方便你理解整体脉络。

浏览器兼容性与环境搭建知识体系 浏览器支持情况 Chrome / Firefox / Safari / Edge getUserMedia兼容性 前缀适配 / Promise包装 本地HTTPS环境 mkcert / 自签名证书 Chrome 28+ / Firefox 22+ / Safari 11+ Edge 79+(Chromium版) 标准API: navigator.mediaDevices 老式前缀: webkit / moz / ms 适配函数: 统一Promise接口 mkcert: 一键生成受信任证书 自签名: openssl + http-server localhost免HTTPS 核心原则:检测 → 适配 → 安全环境 → 错误处理 别让环境问题浪费你的时间

这张图把本章的三个核心模块串起来了。你从浏览器支持开始,然后处理API兼容性,最后搭建安全环境。每一步都有坑,但按这个流程走,基本不会出大问题。

总结一下:

  • 主流浏览器都支持WebRTC,但细节有差异,必须测
  • getUserMedia要写适配函数,兼容老式前缀
  • 本地开发用localhost,部署必须HTTPS
  • mkcert是最省心的HTTPS方案
  • 别忘了加错误处理,用户可能拒绝权限

好了,环境搭好了,下一章咱们就开始写第一个WebRTC Demo。到时候你会发现,前面这些准备工作都是值得的。


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