Node.js 通过https服务器利用js调用网络摄像头

前言
最近写了一个js调用摄像头的代码,整体实现是非常简单,但是放到服务器上,通过外网访问后就会出现一个警告 

我们需要通过js调用摄像头,但在此之前我们需要创建一个https服务器。所以,这篇博文就是帮助大家如何通过js 调用PC端的摄像头。

如何通过js调用摄像头
先看一下js调用摄像头的具体实现。 
整个实现是基于Google提供的webRTC技术,它主要用来让浏览器实时获取和交换视频、音频和数据。 
WebRTC共分三个API。

MediaStream(又称getUserMedia) 
RTCPeerConnection 
RTCDataChannel 
getUserMedia主要用于获取视频和音频信息,后两个API用于浏览器之间的数据交换。

而我们主要了解MediaStream

下面我们直接看代码:

//获取用户设备媒体对象
navigator.getUserMedia({audio:true,video:true},stream => {},err => {});
1
2
我们直接通过navigator.getUserMedia方法就可以获取到用户的媒体对象,这个方法有三个参数。 
①第一个参数为一个JSON对象,主要为了设置是否获取音频或视频流对象 
②获取成功的回调函数,这个回调函数有一个stream参数为获取到的流对象 
③出现错误的回调函数,这个回调函数有一个err错误对象

但是现在想让我们的摄像头拍摄到的画面显示出来,我们可以直接通过h5提供的video标签进行加载播放 
于是我们可以直接在开头加上video标签,并给它一个id 为rtVideo

    <video id="etVideo"></video>
1
我们不添加它的src属性,而是根据js进行动态赋值。

现在我们开始写获取媒体流成功的回调函数

let onSuccess = stream => {
    //获取video的dom对象
    let rtVideo = document.getElementById("rtVideo");
    //为媒体流创建一个url指向
    if(window.URL){
        webcam.src = window.URL.createObjectURL(stream);
    }
    rtVideo.autoplay = true;
}
1
2
3
4
5
6
7
8
9
在上述代码中,由于getUserMedia是异步的,因此,通过getUserMedia获取到的媒体流对象后由事件循环取出,将媒体流对象放入获取成功的回调函数的参数,所以上述的stream参数实质就是我们通过getUserMedia获取到的媒体流对象。 
然后我们通过getElementById();获取到了video的dom对象

    let rtVideo = document.getElementById("rtVideo");
1
下面的代码我们为获取到的流对象创建了一个URL指向,让它可以被传入vedio的src属性。 
window.URL.createObjectURL可以接受一个二进制的流对象作为参数。 
随后我们给rtVideo设置上我们创建的url即可

if(window.URL){
    rtVideo.src = window.URL.createObjectURL(stream);
}
1
2
3
最后我们设置此video为自动播放

rtVideo.autoplay = true;
1
现在在本地运行上述代码时,我们就可以看见摄像头能够正常调用了。但是注意这只是在本地,而被放置在服务器上,通过外网进行访问时,则会报出开头我贴出的那个警告,告知你调用摄像头必须是一个安全的环境比如https。 
下面我们将开始用node.js创建一个https服务器,然后将上述代码通过https服务器返回给客户端。

通过node.js创建https服务器
首先我们得知道https可以看作是一个安全的http服务器,实际上它就是http + ssl/tls协议

创建https服务器必须持有CA机构给出的数字签名才行,这里我们使用openssl进行自签名

step 1:使用openssl创建服务器和客户端的私钥

$ openssl genrsa -out server.key 1024
$ openssl genrsa -out client.key 1024
1
2
step 2:使用openssl分别创建服务器和客户端的公钥

$ openssl rsa -in server.key -pubout -out server.pem
$ openssl rsa -in client.key -pubout -out client.pem
1
2
之后我们需要创建一个CA来自签名我们的数字证书

$ openssl genrsa -out ca.key 1024
$ openssl req -new -key ca.key -out ca.csr
$ openssl x509 req -in ca.csr -signkey ca.key -out ca.crt
1
2
3
随后我们生成服务器的csr数字证书请求文件

$ openssl req -new -key server.key -out server.csr
1
自签名

$ openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -in server.csr -out server.crt
1
到这里我们就已经创建完成一个自签名的服务器数字证书 
需要注意的是,ssl/tls 协议是传输层协议,https基于ssl/tls协议,但是在建立起与客户端的链接时,https 还是会执行tcp的三次经典握手环节,这是因为https本质就是一个安全版的http,并且ssl/tls 提供的仅仅是安全加密这一方面的协议,因此,在建立https服务器的时候,其性能会比http慢半拍,因为在其传输的数据的时候,数据会在传输层加密,每一次传输都会有加密解密的环节,至于这半拍是多少,传送门:http://www.ruanyifeng.com/blog/2014/09/ssl-latency.html

经历了tcp握手,接下来就是https的四次握手 
①客户端生成一个base64编码的随机数,然后将这个随机数随同支持的加密方式,ssl/tls协议的版本号一同发送到服务器 
②服务器生成一个base64编码的随机数,将它和 确认的ssl/tls版本发送到客户端,还会发送一个服务器数字证书 
③客户端回应一个编码改变通知和结束握手通知 
④服务器回应一个编码改变通知和结束握手通知

至此,服务器和客户端握手完毕,值得注意的是,上述握手所传输的信息都是明文传输,但是传输的随机数却会根据RSA 来进行加密,此随机数我们称作 pre master secret ,这个随机数用于生成 session secret ,而session secret是用来利用对称加密来提高加密解密的效率。

至于为什么用三个master secret,这是因为我们的计算机是不会产生真随机数序列,它只会根据一定的算法产生伪随机数序列,一个master secret可能会被猜出来,那三个master secret 就会比较接近随机了。

下面我们利用https 模块来创建一个https服务器,在此之前我需要提一下tls模块,在node中,还封装了一个tls模块,这个模块基于传输层ssl/tls协议的,因此效率比https要高,如同http和tcp 模块。

首先我们引入https模块和fs模块,fs用于读取我们生成的数字证书,私钥,ca的证书等等

//引入模块
const fs = require("fs");
const https = require("https");
1
2
3
导入服务器的私钥和数字证书 
其requestCert 的值为一个Boolean值,当其值为true时,会要求客户端给出相应的证书,默认值为false

//导入服务器的私钥和crt 证书文件
let options = {
    key:fs.readFileSync("./key/server.key"),
    cert:fs.readFileSync("./key/server.crt"),
    requestCert:true,
    ca:[fs.readFileSync("./key/ca.crt")]
};
1
2
3
4
5
6
7
当我们导入options的信息时,我们对请求响应对象的操作与普通http无较大差异

//创建https服务器
let httpsServer = https.createServer(options);

//监听用户连接
httpsServer.on("request",(req,resp) => {
    console.log("有一用户连接");
    resp.setHeader("Content-Type","text/html");
    resp.writeHead(200);
    resp.end(fs.readFileSync("./httpsTest1.html"));
});

httpsServer.listen(9999,"localhost",() => {
    console.log("listening");
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
至此,我们就创建了一个https服务器,上述代码的httpsTest1.html为文章开头的js代码,用于调用摄像头。 
之后我们把代码部署到服务器上,就可以看见成功调用摄像头了,下面贴出完整代码:

node

//引入模块
const fs = require("fs");
const https = require("https");

//导入服务器的私钥和crt 证书文件
let options = {
    key:fs.readFileSync("./key/server.key"),
    cert:fs.readFileSync("./key/server.crt"),
    requestCert:true,
    ca:[fs.readFileSync("./key/ca.crt")]
};

//创建https服务器
let httpsServer = https.createServer(options);

//监听用户连接
httpsServer.on("request",(req,resp) => {
    console.log("有一用户连接");
    resp.setHeader("Content-Type","text/html");
    resp.writeHead(200);
    resp.end(fs.readFileSync("./httpsTest1.html"));
});

httpsServer.listen(9999,"localhost",() => {
    console.log("listening");
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
html/js :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <video id="rtVideo" src=""></video>
    <script type="text/javascript">
        navigator.getUserMedia({audio:true,video:true},stream => {
            //获取video的dom对象
            let rtVideo = document.getElementById("rtVideo");
            //为媒体流创建一个url指向
            if(window.URL){
                rtVideo.src = window.URL.createObjectURL(stream);
            }
            rtVideo.autoplay = true;
        },() => {});
    </script>
</body>
</html>

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值