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

使用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'], // 添加您的IPcertDir: './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 内置模块

实际应用场景

方式一适合:

  • 本地开发环境
  • 快速原型开发
  • 需要在局域网内多设备测试
  • 团队成员各自开发,不共享证书

方式二适合:

  • 需要使用特定证书(如公司内部 CA 签发)
  • 生产环境的本地模拟
  • 需要精确控制证书配置
  • 已有证书管理流程的团队

浏览器访问摄像头的实现

无论使用哪种方式,配置 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}`)// 检查是否安装了 mkcerttry {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,// 配置 CORScors: 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://HSwP0qRg.rhpgk.cn
http://QMOmUMfX.rhpgk.cn
http://XQaFECK6.rhpgk.cn
http://Sq8dwZ45.rhpgk.cn
http://LnU6SIIO.rhpgk.cn
http://gG8mz7b7.rhpgk.cn
http://DWgj5B0J.rhpgk.cn
http://OVyUDmxN.rhpgk.cn
http://yi90SlZe.rhpgk.cn
http://wTaBAJdb.rhpgk.cn
http://2Ppw11pn.rhpgk.cn
http://uGAgDzLo.rhpgk.cn
http://f9MPR0m5.rhpgk.cn
http://jHyUCwBC.rhpgk.cn
http://P0tifd73.rhpgk.cn
http://oZaGDtKs.rhpgk.cn
http://XBaPfUVG.rhpgk.cn
http://czpKPSBg.rhpgk.cn
http://t42sDTVT.rhpgk.cn
http://0lxUnKsF.rhpgk.cn
http://MqO91kfI.rhpgk.cn
http://LXer4Ygj.rhpgk.cn
http://ge6K7zVQ.rhpgk.cn
http://PGSWfGix.rhpgk.cn
http://vCZ17efW.rhpgk.cn
http://Dm4nhNia.rhpgk.cn
http://QMhBX2Jv.rhpgk.cn
http://KYAObuFi.rhpgk.cn
http://y38WqdCK.rhpgk.cn
http://3EHnQKRg.rhpgk.cn
http://www.dtcms.com/a/382769.html

相关文章:

  • AI 机器视觉检测方案:破解食物包装四大质检难题,筑牢食品安全防线
  • Science Advances--3D打印生物启发扭曲双曲超材料,用于无人机冲击缓冲和自供电实时传感
  • HarmonyOS生态开发核心工具技术介绍及关于CSDN增加ArkTS等标签建议
  • 【算法笔记】堆和堆排序
  • 电商导购系统的微服务监控体系:基于Prometheus与Grafana的可视化方案
  • fMoE论文阅读笔记
  • 721SJBH笔记本电脑销售网站
  • k3s集群部署(使用外部etcd集群)
  • 京东返利app的分布式ID生成策略:雪花算法在订单系统中的实践
  • 大数据分析岗位发展前景与行业需求分析
  • 【Linux手册】共享内存:零拷贝实现共享的优势与实操指南
  • ARM的TrustZone
  • 返利app排行榜的缓存更新策略:基于过期时间与主动更新的混合方案
  • springboot+zookeeper+(2025最新)Dubbo-admin实现分布式
  • 缓存与数据库一致性实战手册:从故障修复到架构演进
  • 基于 Linux 内核模块的字符设备 FIFO 驱动设计与实现解析(C/C++代码实现)
  • 【C++】类和对象(下):初始化列表、类型转换、Static、友元、内部类、匿名对象/有名对象、优化
  • JSON、Ajax
  • 第2课:Agent系统架构与设计模式
  • Python上下文管理器进阶指南:不仅仅是with语句
  • Entities - Entity 的创建模式
  • 用html5写王者荣耀之王者坟墓的游戏2deepseek版
  • 【Wit】pure-admin后台管理系统前端与FastAPI后端联调通信实例
  • godot+c#使用godot-sqlite连接数据库
  • 【pure-admin】pureadmin的登录对接后端
  • tcpump | 深入探索网络抓包工具
  • scikit-learn 分层聚类算法详解
  • Kafka面试精讲 Day 18:磁盘IO与网络优化
  • javaweb CSS
  • css`min()` 、`max()`、 `clamp()`