科百科
当前位置: 首页 范文大全

node.js安装教学(在Node.js中创建可恢复的上传器)

时间:2023-06-11 作者: 小编 阅读量: 4 栏目名: 范文大全

为了完成这项任务,我们将完全控制Node.js服务器以请求特定的数据块,HTML表单将接收这些请求并将必要的信息发送到服务器。为了处理这种通信,我们将使用Socket.io。该类FileReader允许我们打开和读取文件的一部分,并将数据作为二进制字符串传递给服务器。这是通过WebSocket协议完成的,该协议是一种与客户端和服务器建立极快的双向连接的方法。现在,我们可以回到HTML文件并定义一些Socket.io事件。

如果您曾经上传过相当大的视频文件,那么您就会知道这种感觉:您已经完成了 90%,但不小心刷新了页面——不得不重新开始。

在本教程中,我将演示如何为您的网站制作一个可以恢复中断的上传并在完成后生成缩略图的视频上传器。

介绍

为了使这个上传器可以恢复,服务器需要跟踪一个文件已经上传了多少,并且能够从它停止的地方继续。为了完成这项任务,我们将完全控制 Node.js 服务器以请求特定的数据块,HTML 表单将接收这些请求并将必要的信息发送到服务器。

为了处理这种通信,我们将使用 Socket.io。如果您从未听说过 Socket.io,它是一个用于在 Node.js 和 HTML 网页之间进行实时通信的框架——我们很快就会对此进行深入研究。

这是基本概念;我们将从 HTML 表单开始。

1.创建 HTML

我将保持 HTML 相当简单;我们需要的只是一个选择文件的输入、一个名称的文本框和一个开始上传的按钮。这是必要的代码:

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8" />

<meta http-equiv="X-UA-Compatible" content="IE=edge" />

<meta name="viewport" content="width=device-width, initial-scale=1.0" />

<title>Resumable Video Uploader</title>

</head>

<body>

<div >

<h2>Video Uploader</h2>

<span >

<label for="FileBox">Choose A File: </label

><input type="file"/><br />

<label for="NameBox">Name: </label

><input type="text"/><br />

<button type="button">Upload</button>

</span>

</div>

</body>

<script type="module">

// put JavaScript code here

</script>

</html>

请注意,我已将内容包装在一个跨度中;稍后我们将使用它来使用 JavaScript 更新页面的布局。我不会在本教程中介绍 CSS,但如果您想使用我的,可以下载源代码。

2.FileReader使用API添加上传按钮

在本教程中,我们将使用FileReader几乎普遍支持的 HTML5 API。

该类FileReader允许我们打开和读取文件的一部分,并将数据作为二进制字符串传递给服务器。这是用于特征检测的 JavaScript:

document.getElementById('UploadButton').addEventListener('click', StartUpload);

document.getElementById('FileBox').addEventListener('change', FileChosen);

上面的代码还向表单中的按钮和文件输入添加了事件处理程序。该FileChosen函数简单地为文件设置一个全局变量——以便我们以后可以访问它——并填写该name字段,以便用户在命名文件时有一个参考点。这是FileChosen功能:

let SelectedFile;

function FileChosen(evnt) {

SelectedFile = evnt.target.files[0];

document.getElementById("NameBox").value = SelectedFile.name;

}

在我们编写StartUpload函数之前,我们必须使用 Socket.io 设置 Node.js 服务器;现在让我们处理一下。

3.创建 Socket.io 服务器

正如我之前提到的,我将使用 Socket.io 在服务器和 HTML 文件之间进行通信。要下载 Socket.io,npm install socket.io请在导航到此项目目录后,在终端窗口中键入(假设您已经安装了 Node.js)。Socket.io 的工作方式是:服务器或客户端“发出”一个事件,然后另一方将以函数的形式接收该事件,并可选择来回传递 JSON 数据。这是通过 WebSocket 协议完成的,该协议是一种与客户端和服务器建立极快的双向连接的方法。使用 WebSockets 的其他一些替代方法是多部分 HTTP 上传和 WebRTC。但是,我们在本教程中只使用 WebSockets。

首先,创建一个空的 JavaScript 文件,并将以下代码放入其中。

const app = require("http").createServer(handler),

{ Server } = require("socket.io"),

fs = require("fs"),

exec = require("child_process").exec,

util = require("util");

const io = new Server(app);

app.listen(8080);

function handler(req, res) {

fs.readFile(__dirname"/index.html", function (err, data) {

if (err) {

res.writeHead(500);

return res.end("Error loading index.html");

}

res.writeHead(200);

res.end(data);

});

}

io.on("connection", function (socket) {

//Events will go here

});

前五行包含所需的库,下一行指示服务器在端口 8080 上侦听,当用户访问该站点时,处理函数只是将我们的 HTML 文件的内容传递给用户。

最后两行是 Socket.io 处理程序,将在有人通过 Socket.io 连接时调用。

现在,我们可以回到 HTML 文件并定义一些 Socket.io 事件。

广告

4.发出一些 Socket.io 事件

要开始在我们的页面中使用 Socket.io,我们首先需要导入它的 JavaScript 库。我们将使用 ESM(浏览器中的新模块规范)来完成此操作。要使用 ESM 导入 Socket.io,我们将在我们正在运行的脚本的开头使用它:

import { io } from "https://cdn.socket.io/4.4.1/socket.io.esm.min.js";

如果您使用的是捆绑器,您也可以socket.io-client从那里安装和导入它。但是,我们不会在本教程中这样做。

现在,我们可以编写StartUpload连接到按钮的函数:

let FReader;

let Name;

function StartUpload() {

if (document.getElementById("FileBox").value != "") {

FReader = new FileReader();

Name = document.getElementById("NameBox").value;

let Content =

"<span id='NameArea'>Uploading "

SelectedFile.name

" as "

Name

"</span>";

Content=

'<div ><div ></div></div><span >0%</span>';

Content=

"<span id='Uploaded'> - <span id='MB'>0</span>/"

Math.round(SelectedFile.size / 1048576)

"MB</span>";

document.getElementById("UploadArea").innerHTML = Content;

FReader.onload = function (evnt) {

socket.emit("Upload", { Name: Name, Data: evnt.target.result });

};

socket.emit("Start", { Name: Name, Size: SelectedFile.size });

} else {

alert("Please Select A File");

}

}

第一行连接到 Socket.io 服务器;接下来,我们为文件读取器和文件名创建了两个变量,因为我们需要对这些变量进行全局访问。在函数内部,我们首先确保用户选择了一个文件,如果他们选择了,我们创建FileReader并使用一个漂亮的进度条更新 DOM。

FileReader 的onload方法在每次读取一些数据时被调用;我们需要做的就是发出一个Upload事件,并将数据发送到服务器。最后,我们发出一个Start事件,将文件的名称和大小传递给 Node.js 服务器。

现在,让我们回到 Node.js 文件,并为这两个事件实现处理程序。

5.处理服务器上的事件

您必须经常清除缓冲区,否则服务器将由于内存过载而崩溃。

socket.io 事件进入我们在 Node.js 文件最后一行的处理程序中。我们要实现的第一个事件是事件,它在用户单击上传按钮Start时触发。

我之前提到过,服务器应该控制它接下来要接收哪些数据;这将允许它从以前不完整的上传继续。它首先确定是否有一个同名的文件没有完成上传,如果是,它将从中断的地方继续;否则,它将从头开始。我们将以半兆字节为增量传递此数据,即 524288 字节。

为了跟踪同时发生的不同上传,我们需要添加一个变量来存储所有内容。在文件的顶部,添加let Files = {};'以下是Start事件的代码:

socket.on("Start", function (data) {

//data contains the variables that we passed through in the html file

const Name = data["Name"];

Files[Name] = {

//Create a new Entry in The Files Variable

FileSize: data["Size"],

Data: "",

Downloaded: 0,

};

let Place = 0;

try {

const Stat = fs.statSync("Temp/"Name);

if (Stat.isFile()) {

Files[Name]["Downloaded"] = Stat.size;

Place = Stat.size / 524288;

}

} catch (er) {} //It's a New File

fs.open("Temp/"Name, "a", 0755, function (err, fd) {

if (err) {

console.log(err);

} else {

Files[Name]["Handler"] = fd; //We store the file handler so we can write to it later

socket.emit("MoreData", { Place: Place, Percent: 0 });

}

});

});

首先,我们将新文件添加到Files数组中,其中包含到目前为止下载的大小、数据和字节数。Place变量存储我们在文件中的位置——它默认为 0,即开始。然后我们检查文件是否已经存在(即它在中间并停止),并相应地更新变量。无论是否是新上传,我们现在打开文件以写入Temp/文件夹,并发出MoreData事件以从 HTML 文件中请求下一部分数据。

现在,我们需要添加Upload事件,如果您还记得的话,每次读取新数据块时都会调用该事件。这是功能:

socket.on("Upload", function (data) {

var Name = data["Name"];

Files[Name]["Downloaded"]= data["Data"].length;

Files[Name]["Data"]= data["Data"];

if (Files[Name]["Downloaded"] == Files[Name]["FileSize"]) {

//If File is Fully Uploaded

fs.write(

Files[Name]["Handler"],

Files[Name]["Data"],

null,

"Binary",

function (err, Writen) {

//Get Thumbnail Here

}

);

} else if (Files[Name]["Data"].length > 10485760) {

//If the Data Buffer reaches 10MB

fs.write(

Files[Name]["Handler"],

Files[Name]["Data"],

null,

"Binary",

function (err, Writen) {

Files[Name]["Data"] = ""; //Reset The Buffer

let Place = Files[Name]["Downloaded"] / 524288;

let Percent =

(Files[Name]["Downloaded"] / Files[Name]["FileSize"]) * 100;

socket.emit("MoreData", { Place: Place, Percent: Percent });

}

);

} else {

let Place = Files[Name]["Downloaded"] / 524288;

let Percent = (Files[Name]["Downloaded"] / Files[Name]["FileSize"]) * 100;

socket.emit("MoreData", { Place: Place, Percent: Percent });

}

});

此代码的前两行使用新数据更新缓冲区,并更新下载的总字节数变量。我们必须将数据存储在缓冲区中并以增量方式保存,以免由于内存过载而导致服务器崩溃;每十兆字节,我们将保存并清除缓冲区。

第一条if语句确定文件是否已完全上传,第二条语句检查缓冲区是否已达到 10 MB,最后,我们请求MoreData,传入完成百分比和要获取的下一个数据块。

现在,我们可以回到 HTML 文件并实现MoreData事件并更新进度。

6.跟踪进度

我创建了一个函数来更新进度条和页面上上传的 MB 量。除此之外,该More Data事件还读取服务器请求的数据块,并将其传递给服务器。

要将文件分割成块,我们使用 File API 的Slice命令。由于 File API 仍在开发中,我们需要分别使用webkitSlice和mozSlice用于 Webkit 和 Mozilla 浏览器。

有了这个最终功能,上传器就完成了!我们剩下要做的就是将完成的文件移出Temp/文件夹并生成缩略图。

7.创建缩略图

在生成缩略图之前,我们需要将文件移出临时文件夹。我们可以通过使用文件流和pump方法来做到这一点。该pump方法接受一个读写流,并缓冲数据。您应该将此代码添加到我在事件中编写“在此处生成缩略图”的位置Upload:

let inp = fs.createReadStream("Temp/"Name);

let out = fs.createWriteStream("Video/"Name);

util.pump(inp, out, function () {

fs.unlink("Temp/"Name, function () {

//This Deletes The Temporary File

//Moving File Completed

});

});

我们添加了 unlink 命令;这将在我们完成复制后删除临时文件。现在进入缩略图:我们将使用 ffmpeg 生成缩略图,因为它可以处理多种格式,并且安装起来很容易。在撰写本文时,还没有任何好的 ffmpeg 模块,因此我们将使用该exec命令,它允许我们从 Node.js 中执行终端命令。有一个很有前途的ffmpeg WASM 端口,将来可能会有意义。如果您没有安装 ffmpeg,请查看ffmpeg 的下载页面。

exec(

"ffmpeg -i Video/"

Name

" -ss 01:30 -r 1 -an -vframes 1 -f mjpeg Video/"

Name

".jpg",

function (err) {

socket.emit("Done", { Image: "Video/"Name".jpg" });

}

此 ffmpeg 命令将在 1:30 标记处生成一个缩略图,并将其以.jpg文件类型保存到Video/文件夹。您可以通过更改参数来编辑缩略图的时间。一旦生成了缩略图,我们就会发出事件。现在,让我们回到 HTML 页面并实现它。-ssDone

8.完成

该Done事件将删除进度条并将其替换为缩略图。因为我们没有设置为静态文件服务器,所以您必须将服务器的位置(例如 Apache)放在Path变量中或配置服务器以提供图像以加载图像。

let Path = "https://localhost/";

socket.on("Done", function (data) {

const Content = "Video Successfully Uploaded !!";

Content=

"<img id='Thumb' src='"

Path

data["Image"]

"' alt='"

Name

"'><br>";

Content=

"<button type='button' name='Upload' value='' id='Restart' class='Button'>Upload Another</button>";

document.getElementById("UploadArea").innerHTML = Content;

document.getElementById("Restart").addEventListener("click", Refresh);

});

上面,我们添加了一个按钮来开始上传另一个文件;所有这一切都是刷新页面。

结论

这就是它的全部内容,但是,当然,当您将它与数据库和 HTML5 播放器配对时,您可以想象其可能性!

    推荐阅读
  • 如何一天过计算机二级()

    ✅距离计算机二级考试仅剩最后28天❗️❗️一个月应该如果复习备考背景:二战通过计算机二级,期间踩过不少坑,最后各种总结经验练题,在考场上word和excel都抽到了原题,最后终于拿到了证书我给大家总结。

  • 肥花甲做法(花甲如何做好吃)

    以下内容大家不妨参考一二希望能帮到您!肥花甲做法原料:花甲、青辣椒、蒜、姜、豆豉、酱油。首先,需要把花甲清洗干净。之后,再锅烧热倒入油爆香。炒香后加入适量的清水和少量酱油煮最后,花甲笑开口就是熟了。

  • 满江红胸怀大志(满江红白衣天使出征)

    为鼓舞抗疫斗志,坚定抗疫信心,人民网联合《中国作家》杂志社联合发起“人民战‘疫’”征文,向全国作家和网友发出邀约,鼓励大家用手中的笔,记录这场防疫阻击战中值得铭记的时刻。突如其来、漫卷全国的新型冠状病毒感染的肺炎疫情,牵动着党中央和全国人民的心。防控感染、抗击疫情,成为全国上下的心之所向。

  • 成都到四姑娘山自驾游要多久(成都到四姑娘山)

    成都到四姑娘山自驾游要多久位于四川省阿坝藏族羌族自治州小金县四姑娘山镇境内的四姑娘山风景区,总共由四座绵延不断的山峰组成,分别为幺姑娘山也称幺妹峰、三姑娘山、二姑娘山以及大姑娘山,其中幺姑娘山海拔约6250米,是四川的第二高峰,。中午可返回硗碛藏寨去往当地特色牧场品尝特色藏香猪汤锅,还可以取采摘生态蔬菜。

  • 学校体育课主要有几种形式(每天一节体育课)

    因为今年6月,滨江区曾专门出台意见,要求区内每校推一个年级,实施“每天一节体育课”,“每天校内体育锻炼1.5小时”。起步阶段,部分学校进行全校试点,即所有年级均实施“每天一节体育课”,闻涛小学就是其中之一。新学期开始,学校实施每天一节体育课,意味着一、二年级的体育课从每周四节增加到五节,两个年级一共12个班,对体育老师来说,相当于每周多了12节课。

  • 关于猴子的心情短语(关于关于猴子的心情短语)

    关于猴子的心情短语说白了不就是自己被人当猴耍了还以为自己是看戏的那个人呗。被人当猴耍玩一次就够了,居然又被人当猴耍了。我是啥话也不想说了,以后这样的人,我会离的远远的。这种所谓的朋友,帮帮忙,还是不要了。亏了一个车位的钱、还高兴的像个傻子。这叫吃你豆腐,薅你羊毛,捏你蛋蛋,被人当猴耍了。是我傻,没脑子,被人当猴耍了还挺认真卖力的,人呐还是狠点好。

  • 干桑叶粉的食用方法(桑叶粉怎么食用方法)

    很多人听说干桑叶粉是一种能保健身体的保健食材,就想在日常生活中多食用一些,但对他的食用方法人们了解并不多,今天我会做详细介绍,能让大家知道干桑叶粉应该怎么吃,同时也会让大家了解干桑叶粉的制作方法,以后再需要时,大家就可以自己在家中制作干桑叶粉。

  • 如何删除桌面上win7自带的ie图标(Win7系统桌面上的IE图标删除不了怎么办)

    win7系统桌面上的IE图标删除不了怎么办?接下来就为大家简单介绍一下方法吧!

  • 汽车6个常见故障的快速解决的办法

    除此之外也可能是活塞环或发动机磨损导致的,需要现场检查后才能确定故障点和维修费用。另外检查刹车总泵杂质是否过多、漏油,真空助力泵是否失效。当新更换轮胎或补胎后均应重新调整轮胎动平衡量。一旦发现变速箱油温过热报警,必须立即靠边停车散热。

  • 80年代家里小时候做的好吃的(餐桌上的保留项目东北老式光头)

    ,接下来我们就来聊聊关于80年代家里小时候做的好吃的?以下内容大家不妨参考一二希望能帮到您!