JavaScript 文件上传完整指南,附【图书中奖者名单】
来源 | https://betterprogramming.pub/a-complete-guide-of-file-uploading-in-javascript-2c29c61336f5
翻译 | 杨小爱
文件上传是 Web 项目的常用功能。相信大家在开发过程中或多或少都遇到过相关的需求。
在今天的这篇文章中,我总结了一些场景和解决方案,希望能帮助你彻底掌握文件上传相关的问题。
我们的目标
首先,我们来明确一下文件上传的具体功能。
根据上传目标,有3种任务:
上传单个文件
同时上传多个文件
上传整个文件夹
根据用户操作,有:
选择要上传的文件
将文件拖到框中然后上传
从剪贴板上传
从性能的角度来看,我们可能需要:
压缩文件后上传
将大文件分成块然后上传
另外,有时我们可能不会在客户端浏览器上传文件,而是通过服务器上传到另一台服务器。
我们将依次讨论这些。
准备工作
在开始编程工作之前,我们还是需要了解一些背景知识。
首先,在上传文件时,我们使用最流行的 HTTP 库 Axios。在实际开发中,我们一般不直接使用 XMLHttpRequest,使用 Axios 符合真实的开发模式。
当我们在前端讨论上传文件的时候,要想全面了解相关原理,就必须了解相关的后端代码。这里我们使用 Koa 来实现我们的服务器。
最后希望大家对formdata有一个简单的了解,我们使用这种数据格式来上传文件。
上传单个文件
传单个文件的需要太常见了。例如,当我们注册微信后,我们可能需要上传更改一个头像。
文件上传功能需要客户端和服务器的配合。在我们的项目中,用户在客户端选择一个文件,然后上传到服务器;服务器保存文件并返回它的 URL。
这是项目预览:
上面的 Gif 展示了文件上传的完整过程:
用户在浏览器中选择文件
用户点击上传按钮
上传的文件放在服务器的uploadFiles文件夹中
然后服务器返回一个URL,就是上传文件的地址
用户可以通过这个 URL 访问资源
编码
这个项目的所有代码都保存在 GitHub 上:
你可以将其克隆到你的计算机:
# clone it
$ git clone git@github.com:BytefishMedium/FileUploading.git
# and install npm package
$ cd FileUloading
$ npm install
所有与单个文件上传相关的代码都放在 1-SingleFile 文件夹中。
client.html 与客户端代码相关。
server.js 与服务器端代码相关
要运行服务器,你可以转到该文件夹并运行以下命令:
$ node server.js
然后,我们可以在任何浏览器上打开 client.html。
具体操作我已经在上面的gif中展示过了。你可以先自己尝试一下,然后继续阅读。
客户端代码
嗯,把大象放进冰箱需要多少步骤?
只需三步:
打开冰箱门
把大象放进去
关上门。
上传文件也是如此,我们只需要三个步骤:
让用户选择要上传的文件
阅读此文件
使用axios上传文件
在 HTML 中,我们可以使用 input 元素。只需将此元素的类型设置为文件,然后该元素即可用于选择文件。
<input id="fileInput" type="file"/>
用户选择文件后,该文件的元数据将存储在此输入元素的 files 属性中。
const uploadFileEle = document.getElementById("fileInput")
console.log(uploadFileEle.files[0]);
最后,我们使用 Axios 的 post 方法来上传文件。但是在上传文件之前,我们还需要把这个文件打包成FormData格式。
let file = fileElement.files[0];
let formData = new FormData();
formData.set('file', file);
axios.post("http://localhost:3001/upload-single-file", formData).then(res => {console.log(res)
})
提示:FormData 是一种键值类型的数据格式。这是一个例子:
好了,这些就是文件上传相关的知识点了,更完整的代码如下:
<!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>Document</title><script src=" https://unpkg.com/axios@0.24.0/dist/axios.min.js"></script>
</head><body><input type="file" id="fileInput"><button id="uploadButton">upload</button><script>document.getElementById("uploadButton").onclick = () => {let fileElement = document.getElementById('fileInput')// check if user had selected a fileif (fileElement.files.length === 0) {alert('please choose a file')return}let file = fileElement.files[0]let formData = new FormData();formData.set('file', file);axios.post("http://localhost:3001/upload-single-file", formData, {onUploadProgress: progressEvent => {const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);console.log(`upload process: ${percentCompleted}%`);}}).then(res => {console.log(res.data)console.log(res.data.url)})}
</script>
</body></html>
这段代码其实就是为了实现我们之前说的三个步骤:
只是我们增加了两个额外的功能:
一是上传按钮。当用户点击上传按钮时,我们开始执行上传逻辑。
然后我们再做一个判断,确保用户真的选择了一个文件。
然后,当axios上传文件时,它可以让我们监控文件上传的进度。
我们知道 HTTP 是建立在 TCP 之上的。如果一个HTTP报文比较大,可能会分解成多个不同的TCP报文在网络中传输。
如果你需要写一个进度条来向用户展示上传的进度,你可以使用这个 API。
axios.post("http://localhost:3001/upload-single-file", formData, {onUploadProgress: (progressEvent) => {const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);console.log(`upload process: ${percentCompleted}%`);},
});
progressEvent.loaded 表示上传成功的字节数,progressEvent.total 表示文件的总字节数。
好的,这是我们的客户端代码。
服务器端代码
要启动服务器,我们可以使用 Koa。这是一个使用 Koa 的小型服务器:
const path = require("path");
const Koa = require("koa");
const Router = require("@koa/router");const app = new Koa();
const router = new Router();const PORT = 3000;router.get("/", async (ctx) => {ctx.body = "Hello friends!";
});app.use(router.routes()).use(router.allowedMethods());app.listen(PORT, () => {console.log(`app starting at port ${PORT}`);
});
view rawkoa.server.v1.js hosted with ❤ by GitHub
这是最基本的 Koa 演示。由于本文重点介绍文件上传,所以我就不详细解释了。如果你不熟悉这个,你可以阅读官方文档。
Koa:https://github.com/koajs/koa
Koa-router:https://github.com/koajs/router
我们的客户端使用FormData的格式上传文件,那么,我们的服务器也需要解析FormData。而 Koa-multer 是一个帮助我们解析 FormData 数据的中间件:
const path = require("path");
const Koa = require("koa");
const Router = require("@koa/router");
const multer = require("@koa/multer");
const cors = require("@koa/cors");const app = new Koa();
const router = new Router();const PORT = 3000;const upload = multer();router.get("/", async (ctx) => {ctx.body = "Hello friends!";
});// add a route for uploading single files
router.post("/upload-single-file", upload.single("file"), (ctx) => {console.log("ctx.request.file", ctx.request.file);ctx.body = `file ${ctx.request.file.filename} has saved on the server`;
});app.use(cors());
app.use(router.routes()).use(router.allowedMethods());app.listen(PORT, () => {console.log(`app starting at port ${PORT}`);
});
关于 Koa-multer,你可以阅读他们的官方文档:
Koa-multer:https://github.com/koajs/multer
Multer:https://github.com/expressjs/multer
关键代码是uoload.single('file'),这行代码可以帮助我们解析FormData的数据,然后,把对应的信息放到ctx.request.file中。
其实,此时我们的服务器已经可以接收到客户端上传的文件了,但是,接收到文件后并没有存储到磁盘中。
如果我们想让 Koa-multer 为我们将文件保存到磁盘,我们可以添加以下配置:
const storage = multer.diskStorage({destination: function (req, file, cb) {cb(null, UPLOAD_DIR);},filename: function (req, file, cb) {cb(null, `${file.originalname}`);},
});
const upload = multer({ storage: storage });
完整的代码是 server.js,你可以直接在代码仓库中阅读。
当前的流程图如下所示:
无论如何,我们应该自己尝试一下。
上传多个文件
有了上面的基础,我们编写上传多个文件的代码就简单多了。
首先,我们需要修改 input 元素并为其添加 multiple 属性。
<input type="file" id="fileInput" multiple>
这是告诉浏览器现在这个输入元素应该允许用户同时选择多个文件。
然后用户选择多个文件后,数据会放在fileElement.files中。我们在构造formdata的时候,需要遍历这个列表,把所有的文件都放到formdata中。
let files = Array.from(fileElement.files);
let formData = new FormData();
files.forEach((file) => {formData.append("file", file);
});
那么上传文件的代码就不需要修改了。
这是完整的代码:
该文件位于项目中的 2-MultipleFiles/client.html 上。
同时,我们还需要调整服务端的代码。
首先,我们需要添加对应的路由/upload-multiple-files
, 然后使用 upload.fields([{ name: “file” }]) 中间件来处理多个文件。之后request中的FormData数据会被放到ctx.files.file中。
演示:
上传目录
现在让我们看一下上传目录的步骤。
与之前类似,我们需要将 input 元素的属性设置为:
<input type="file" id="fileInput" webkitdirectory>
那么在上传目录的时候,input元素的files对象会有webkitRlativePath属性,我们也将它们添加到formdata中。
这里需要注意的是,当文件名中包含\时,koa-multer可能会报错。要解决此问题,我们需要将 \ 替换为 @ 符号。
formData.append('file', file, file.webkitRelativePath.replace(/\//g, "@"));
那么我们还需要修改对应的服务器代码:
演示:
总结
我们依次分析了上传单个文件、多个文件、目录的过程。其实很简单,只要3步:
使用输入元素让用户选择文件
读取文件并构造FormData
使用 Axios 上传 FormData
所有代码都在 GitHub 上,大家可以自己试试。如果您有任何问题,可以发表评论。
由于文章篇幅关系,剩下的文件上传会在后面的文章中介绍,如果您对此内容感兴趣,可以关注我,感谢你的阅读。
PS:
免费送书活动的中奖名单如下:
@Echo、@Mint、@知己、@璐、@Mr.simple、@咩咩咩 。
另外,因为合作出版社根据我们这边活动的阅读情况,又额外增加了2个名额,所以,还是一样按照规则顺序下来,这两位惊喜幸运者是,
@
PHP实现视频文件上传完整实例, 本文以一个完整实例的形式实现了视频文件上传的功能.虽然是比较基础的应用,仍有一定的参考价值.分享给大家供大家参考之用.具体方法如下: 首先,对PHP来说视频也属于文件 ... Github 之 本地上传代码到 github ,并且添加 .gitignore 文件 屏蔽一些文件上传(内附详细步骤) 目录 Github 之 本地上传代码到 github ,并且添加 .gitig ... SWFUpload是一个flash和js相结合而成的文件上传插件,其功能非常强大.以前在项目中用过几次,但它的配置参数太多了,用过后就忘记怎么用了,到以后要用时又得到官网上看它的文档,真是太烦了.所以 ... 首先,我这里使用的是 Jquery Uploadify3.2版本号 导入相关的CSS JS <link rel="stylesheet" type=" ... 版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/shanhuhau/article/details/28617999 首先须要引入上传控件 <s ... 使用javascript原生功能实现,点击上传文件,然后再网页上显示出来 1. 初级显示 1.1 准备一个input标签和一个img标签 <input type=file id="fi ... 本文为 Qunar 技术沙龙投稿,版权归原作者所有,未经允许,请勿转载. 原文地址:http://mp.weixin.qq.com/s/KWFyJa06CNXrU8zhSzzQFQ 作者:梁志,201 ... 这里有新鲜揭晓的PHP面向对象编程,程序猫速率看过来! PHP开源脚本语言PHP(外文名: Hypertext Preprocessor,中文名:"超文本预处理器")是一种通用开源 ... 在app.json里面加如下代码, 使用 WeUI组件库.点击跳转 "useExtendedLib": {"weui": true}, 先看效果图 wxml & ... 摘要 MetInfo 23号发布了新版本5.1.5,修补了本文提到的漏洞,当然严格来说应该是任意变量覆盖漏洞-. ps:欢迎各种形式转载,首发t00ls.net MetInfo 23号发布了新版本5. ...JavaScript 文件上传完整指南,附【图书中奖者名单】相关推荐
最新文章
热门文章