当前位置: 首页 > news >正文

使用HTTPS 服务在浏览器端启用摄像头的方式解析

使用HTTPS 服务在浏览器端启用摄像头的方式解析

1.方式1

// vite.config.js
import { defineConfig
} from 'vite'
import vue from '@vitejs/plugin-vue'
import basicSsl from '@vitejs/plugin-basic-ssl'
export default defineConfig({
plugins: [
vue(),
basicSsl({
name: 'test',
domains: ['192.168.15.166', 'localhost'], // 添加您的IP
certDir: './cert',
}),
],
server: {
host: '0.0.0.0',
port: 3000,
https: true,
proxy: {
'/api': {
target: 'http://localhost:5000',
changeOrigin: true,
},
},
},
build: {
outDir: 'dist',
assetsDir: 'assets',
sourcemap: false,
minify: 'terser',
rollupOptions: {
output: {
chunkFileNames: 'js/[name]-[hash].js',
entryFileNames: 'js/[name]-[hash].js',
assetFileNames: '[ext]/[name]-[hash].[ext]',
},
},
},
})

2.方式2

// vite.config.js
import { defineConfig
} from 'vite'
import vue from '@vitejs/plugin-vue'
import fs from 'fs'
import path from 'path'
export default defineConfig({
plugins: [
vue(),
],
server: {
https: {
key: fs.readFileSync(path.resolve(__dirname, 'cert/key.pem')),
cert: fs.readFileSync(path.resolve(__dirname, 'cert/cert.pem'))
},
host: '0.0.0.0',
port: 3000,
proxy: {
'/api': {
target: 'http://localhost:5000',
changeOrigin: true
},
},
},
build: {
outDir: 'dist',
assetsDir: 'assets',
sourcemap: false,
minify: 'terser',
},
})

这两个 Vite 配置文件都实现了 HTTPS 服务,这是浏览器访问摄像头等敏感设备的必要条件。以下详细解释它们的原理和差异。

为什么需要 HTTPS

现代浏览器出于安全考虑,要求在以下情况下才能访问摄像头、麦克风等敏感设备:

  • 使用 HTTPS 协议(安全连接)
  • 或者是 localhost 域名(本地开发特例)

这是因为 getUserMedia() API 被归类为"强大功能"(Powerful Features),需要安全上下文(Secure Context)。

方式一:使用 @vitejs/plugin-basic-ssl 插件

plugins: [
vue(),
basicSsl({
name: 'test',
domains: ['192.168.31.179', 'localhost'],
certDir: './cert',
}),
]

原理:

  1. 自动生成证书:插件会自动为指定的域名生成自签名 SSL 证书
  2. 证书存储:生成的证书存储在 ./cert 目录中
  3. 多域名支持:可以为多个域名/IP 生成证书(如局域网 IP 和 localhost)
  4. 自动配置:插件会自动将证书配置到 Vite 的 HTTPS 服务器

工作流程:

  • 首次运行时,插件检查证书是否存在
  • 如果不存在,使用内置的证书生成器创建自签名证书
  • 将证书自动注入到 Vite 的 server 配置中
  • 后续运行时复用已生成的证书

方式二:手动配置证书

server: {
https: {
key: fs.readFileSync(path.resolve(__dirname, 'cert/key.pem')),
cert: fs.readFileSync(path.resolve(__dirname, 'cert/cert.pem'))
},
}

原理:

  1. 手动管理证书:需要预先生成或获取 SSL 证书文件
  2. 文件读取:使用 Node.js 的 fs 模块直接读取证书文件
  3. 直接配置:将证书内容直接传递给 Vite 的 HTTPS 配置

证书生成方式(通常使用 OpenSSL):

# 生成私钥
openssl genrsa -out key.pem 2048
# 生成证书
openssl req -new -x509 -key key.pem -out cert.pem -days 365

关键差异对比

特性方式一(plugin-basic-ssl)方式二(手动配置)
便利性高 - 自动生成和管理低 - 需要手动创建证书
灵活性中等 - 插件预设配置高 - 完全自定义
证书类型自签名证书可以使用任何证书(自签名或CA签发)
多域名支持内置支持,配置简单需要生成包含 SAN 的证书
首次设置零配置,自动完成需要手动生成证书
团队协作每个开发者自动生成需要共享证书文件
证书更新删除旧证书即可重新生成手动重新生成和替换
依赖性需要安装额外插件仅需 Node.js 内置模块

实际应用场景

方式一适合:

方式二适合:

浏览器访问摄像头的实现

无论使用哪种方式,配置 HTTPS 后都可以使用以下代码访问摄像头:

navigator.mediaDevices.getUserMedia({
video: true,
audio: true
})
.then(stream =>
{
// 获取到媒体流
videoElement.srcObject = stream;
})
.catch(err =>
{
console.error('无法访问摄像头:', err);
});

注意事项

  1. 证书信任:两种方式生成的自签名证书都会导致浏览器警告,需要手动信任
  2. 局域网访问:方式一通过配置 IP 地址,可以让局域网内其他设备通过 HTTPS 访问
  3. 安全性:这些配置仅适用于开发环境,生产环境应使用正规 CA 签发的证书

总的来说,方式一更适合快速开发和原型验证,方式二则提供了更多的控制权和灵活性。选择哪种方式主要取决于项目需求和团队的技术偏好。

这是使用自签名证书进行本地开发时的常见问题。让我详细说明解决方案:

一、手机无法访问的问题排查

1. 确保网络连通性

// vite.config.js
server: {
host: '0.0.0.0', // 允许外部访问
port: 3000,
https: true,
}

检查步骤:

  • 确保手机和电脑在同一局域网
  • 电脑防火墙允许 3000 端口
  • 使用电脑的局域网 IP(如 https://192.168.31.179:3000

2. 防火墙设置

# Windows - 以管理员运行
netsh advfirewall firewall add rule name="Vite Dev Server" dir=in action=allow protocol=TCP localport=3000
# macOS
sudo pfctl -d # 临时关闭防火墙测试
# Linux
sudo ufw allow 3000/tcp

二、手机端安装证书的正确方法

iOS 设备

  1. 生成包含正确信息的证书:
# 创建证书配置文件 cert.conf
cat > cert.conf <<
EOF
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
C = CN
ST = State
L = City
O = Organization
CN = 192.168.31.179
[v3_req]
keyUsage = critical, digitalSignature, keyAgreement
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
IP.1 = 192.168.31.179
IP.2 = 127.0.0.1
EOF
# 生成证书
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout key.pem -out cert.pem -config cert.conf
  1. 安装证书到 iOS:
  • cert.pem 文件通过邮件/AirDrop 发送到手机
  • 点击证书文件,选择"安装"
  • 设置 → 通用 → 关于本机 → 证书信任设置
  • 开启对该证书的完全信任

Android 设备

  1. Android 安装步骤:
  • cert.pem 重命名为 cert.crt
  • 传输到手机
  • 设置 → 安全 → 加密与凭据 → 安装证书 → CA 证书
  • 选择证书文件安装

三、使用 mkcert 工具(推荐方案)

mkcert 可以创建本地受信任的证书,避免所有警告:

安装 mkcert

# Windows (使用 Chocolatey)
choco install mkcert
# macOS
brew install mkcert
# Linux
apt install libnss3-tools
wget -O mkcert https://github.com/FiloSottile/mkcert/releases/download/v1.4.4/mkcert-v1.4.4-linux-amd64
chmod +x mkcert
sudo mv mkcert /usr/local/bin/

配置本地 CA 并生成证书

# 1. 安装本地 CA
mkcert -install
# 2. 生成证书(包含所有需要的域名和 IP)
mkcert -cert-file cert.pem -key-file key.pem localhost 127.0.0.1 192.168.31.179 ::1
# 3. 为手机生成 CA 证书
mkcert -CAROOT # 显示 CA 证书位置

更新 Vite 配置

// vite.config.js
import { defineConfig
} from 'vite'
import vue from '@vitejs/plugin-vue'
import fs from 'fs'
import path from 'path'
export default defineConfig({
plugins: [vue()],
server: {
https: {
key: fs.readFileSync('./key.pem'),
cert: fs.readFileSync('./cert.pem')
},
host: '0.0.0.0',
port: 3000,
}
})

手机端信任 mkcert CA

  1. 获取 CA 证书:
# 找到 CA 证书位置
mkcert -CAROOT
# 通常在: 
# Windows: %LOCALAPPDATA%\mkcert
# macOS: ~/Library/Application Support/mkcert
# Linux: ~/.local/share/mkcert
  1. rootCA.pem 发送到手机并安装

四、使用 ngrok(外网访问方案)

如果证书问题难以解决,可以使用 ngrok 提供的 HTTPS 隧道:

# 安装 ngrok
npm install -g ngrok
# 启动本地服务后,创建隧道
ngrok http 3000
# 会得到类似这样的地址:
# https://abc123.ngrok.io

优点:

  • 自动 HTTPS,无需证书配置
  • 可以外网访问
  • 手机无需安装证书

五、开发环境最佳实践配置##

// vite.config.js - 完整的 HTTPS 配置方案
import { defineConfig
} from 'vite'
import vue from '@vitejs/plugin-vue'
import fs from 'fs'
import path from 'path'
import { execSync
} from 'child_process'
// 获取本机局域网 IP
function getLocalIP() {
const os = require('os')
const interfaces = os.networkInterfaces()
for (const name of Object.keys(interfaces)) {
for (const iface of interfaces[name]) {
if (iface.family === 'IPv4' &&
!iface.internal) {
return iface.address
}
}
}
return '127.0.0.1'
}
// 自动生成证书函数
function ensureCertificates() {
const certDir = path.resolve(__dirname, 'cert')
const keyPath = path.join(certDir, 'key.pem')
const certPath = path.join(certDir, 'cert.pem')
// 检查证书是否存在
if (fs.existsSync(keyPath) && fs.existsSync(certPath)) {
console.log('✅ 使用现有证书')
return { key: keyPath, cert: certPath
}
}
// 创建证书目录
if (!fs.existsSync(certDir)) {
fs.mkdirSync(certDir, { recursive: true
})
}
const localIP = getLocalIP()
console.log(` 局域网 IP: ${localIP
}`)
// 检查是否安装了 mkcert
try {
execSync('mkcert -version', { stdio: 'ignore'
})
console.log(' 使用 mkcert 生成受信任的证书...')
// 安装本地 CA(如果还没安装)
execSync('mkcert -install', { stdio: 'inherit'
})
// 生成证书
execSync(
`mkcert -cert-file ${certPath
} -key-file ${keyPath
} localhost 127.0.0.1 ${localIP
} ::1`,
{ stdio: 'inherit'
}
)
console.log('✅ mkcert 证书生成成功!')
console.log(' 手机端请安装 CA 证书:')
const caRoot = execSync('mkcert -CAROOT').toString().trim()
console.log(` ${path.join(caRoot, 'rootCA.pem')
}`)
} catch (e) {
console.log('⚠️ mkcert 未安装,使用 OpenSSL 生成自签名证书...')
// 创建 OpenSSL 配置
const configPath = path.join(certDir, 'openssl.cnf')
const opensslConfig = `
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
C = CN
ST = State
L = City
O = Dev Organization
CN = ${localIP
}
[v3_req]
keyUsage = critical, digitalSignature, keyAgreement
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
DNS.2 = *.localhost
IP.1 = 127.0.0.1
IP.2 = ${localIP
}
IP.3 = ::1
`
fs.writeFileSync(configPath, opensslConfig)
// 生成证书
try {
execSync(
`openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ${keyPath
} -out ${certPath
} -config ${configPath
}`,
{ stdio: 'inherit'
}
)
console.log('✅ 自签名证书生成成功!')
console.log('⚠️ 浏览器会显示安全警告,需要手动信任证书')
} catch (error) {
console.error('❌ 证书生成失败:', error)
process.exit(1)
}
}
return { key: keyPath, cert: certPath
}
}
// 生成或获取证书
const certificates = ensureCertificates()
export default defineConfig({
plugins: [vue()],
server: {
https: {
key: fs.readFileSync(certificates.key),
cert: fs.readFileSync(certificates.cert)
},
host: '0.0.0.0', // 允许外部访问
port: 3000,
// 显示二维码方便手机扫描
open: false,
// 配置 CORS
cors: true,
// 代理配置
proxy: {
'/api': {
target: 'http://localhost:5000',
changeOrigin: true,
secure: false,
}
}
},
// 构建配置
build: {
outDir: 'dist',
assetsDir: 'assets',
sourcemap: false,
minify: 'terser',
rollupOptions: {
output: {
chunkFileNames: 'js/[name]-[hash].js',
entryFileNames: 'js/[name]-[hash].js',
assetFileNames: '[ext]/[name]-[hash].[ext]',
}
}
},
// 优化配置
optimizeDeps: {
exclude: ['vue']
}
})
// 启动后打印访问信息
process.nextTick(() =>
{
const localIP = getLocalIP()
console.log('\n 服务已启动:')
console.log(` 本地: https://localhost:3000`)
console.log(` 局域网: https://${localIP
}:3000`)
console.log('\n 手机访问提示:')
console.log(' 1. 确保手机与电脑在同一 WiFi')
console.log(' 2. 如有证书警告,点击"高级"→"继续访问"')
console.log(' 3. iOS 需在"设置"→"通用"→"关于本机"→"证书信任设置"中信任证书\n')
})

六、配套的 package.json 脚本

{
"scripts": {
"dev": "vite",
"dev:host": "vite --host",
"dev:network": "vite --host 0.0.0.0",
"dev:https": "node scripts/setup-https.js && vite",
"cert:install": "mkcert -install",
"cert:generate": "mkcert -cert-file cert/cert.pem -key-file cert/key.pem localhost 127.0.0.1 $(ipconfig getifaddr en0 || hostname -I | awk '{print $1}') ::1",
"cert:trust": "mkcert -install && npm run cert:generate",
"build": "vite build",
"preview": "vite preview",
"tunnel": "ngrok http 3000"
},
"devDependencies": {
"@vitejs/plugin-basic-ssl": "^1.0.1",
"@vitejs/plugin-vue": "^4.2.3",
"vite": "^4.3.9",
"vue": "^3.3.4"
},
"dependencies": {
"qrcode": "^1.5.3"
}
}

七、快速解决方案总结

最简单的方案(推荐)

  1. 安装 mkcert
# 一次性设置,永久解决证书问题
brew install mkcert # macOS
mkcert -install
  1. 生成证书
mkcert -cert-file cert.pem -key-file key.pem localhost 192.168.xxx.xxx
  1. 手机端信任
  • ~/.local/share/mkcert/rootCA.pem(或对应系统路径)发送到手机
  • 安装为受信任的 CA 证书

故障排查清单

网络连接

  • 手机和电脑同一 WiFi?
  • 防火墙允许 3000 端口?
  • 使用正确的 IP 地址?

证书配置

  • 证书包含局域网 IP?
  • 证书已安装到手机?
  • iOS 已在"证书信任设置"中启用?

Vite 配置

  • host: '0.0.0.0' 已设置?
  • https: true 或手动配置证书?
  • 端口没有被占用?

终极备用方案

如果以上都不行,使用 localtunnelngrok

npx localtunnel --port 3000 --subdomain myapp
# 或
ngrok http 3000

这样可以获得一个临时的公网 HTTPS 地址,无需任何证书配置,手机可以直接访问。

主要缺点是需要依赖外部服务,并且速度可能较慢。但对于紧急测试和演示,这是最快的解决方案。

http://www.wxhsa.cn/company.asp?id=5679

相关文章:

  • 5分钟SAE极速部署Dify,高效开发AI智能体应用
  • .NET驾驭Word之力:理解Word对象模型核心 (Application, Document, Range)
  • 事件轮循机制EventLoop
  • ruoyi-vue初步接触
  • AT_arc180_c [ARC180C] Subsequence and Prefix Sum
  • 如何快速看懂「祖传项目」?Qoder 强势推出新利器
  • 测试不再碎片化:AI智能体平台「项目资料套件」功能上线!
  • 大模型与知识图谱驱动测试公开课
  • 上位机项目展示
  • 美化自己的Github主页-Github profile页面仓库使用指南
  • 充气泵方案:充气泵用数字传感器有什么好处?
  • windows系统下anaconda的安装和使用
  • Lock分析:systemstate分析row cache lock
  • mysql查看连接数,从查询到优化
  • 遗传算法与偏最小二乘结合的化学光谱变量选择方法
  • 云剪贴板
  • 读书笔记:Oracle数据库的水位线秘密:为什么空表查询还很慢?
  • AI测试平台自动遍历:低代码也能玩转全链路测试
  • 0代码5分钟一键生成Springboot+Vue后台管理系统
  • nvm与node.js的安装指南
  • 故障处理:2分钟处理Oracle RAC中OCR磁盘组丢失磁盘的故障
  • Saga分布式事务框架执行逻辑
  • 在Android开发中实现两个Intent跳转及数据交换的方法
  • ARC188 做题记
  • AT_arc145_d [ARC145D] Non Arithmetic Progression Set
  • Microsoft AI Genius | 第三集实战课正式开启:用 Copilot Studio 定制你的专属智能体
  • C# 多线程编程核心要点:不只是Thread和lock
  • 基于MATLAB的图像融合拼接GUI系统设计
  • Python使用多线程和异步调用
  • 研究生学术英语读写教程(中国科学院大学出版) Unit10 TextA 原文以及翻译(仅供学习)