Ajax异步文件上传与NodeJS express服务端处理


Posted in NodeJs onApril 01, 2017

为了避免在实现简单的异步文件上传功能时候引入一个第三方库文件的尴尬情形(库文件可能造成多余的开销,拉低应用加载速度,尤其是在引入库文件之后仅使用其中一两个功能的情况下,性价比极低),最近了解了一下文件异步上传的实现原理,顺带看了看进度条、图片预览等功能的实现,做一点简单的整理。

文件上传

HTML结构如下,一个file input和一个button。当点击“上传”按钮的时候,将file input选中的文件上传到服务器。

<input type="file" name="file" id="file" />
<button id="upload">上传</button>

以下是“上传”按钮的点击事件处理器,点击按钮之后通过一个XMLHttpRequest对象来实现发送异步请求。上传的内容为文件,因此还需要用到FormData对象,FormData可以js里面创建表单对象,将file input的文件append到FormData对象中,最后调用XHR对象的send()方法将表单数据发送出去即可。

var file = document.querySelector('#file');
var upload = document.querySelector('#upload');
var xhr = new XMLHttpRequest();

// 点击上传
function uploadFile(event) {
 var formData = new FormData();
 formData.append('test-upload', file.files[0]);
 xhr.onload = uploadSuccess;
 xhr.open('post', '/upload', true);
 xhr.send(formData);
}
// 成功上传
function uploadSuccess(event) {
 if (xhr.readyState === 4) {
 console.log(xhr.responseText);
 }
}

上传进度

在进行文件上传的时候,xhr对象会有一个upload属性,会提供一个progress事件,在相应的事件处理器里面通过事件对象可以知道当前的上传进度,利用这个特点可以很方便地实现进度条或者进度提示。

<input type="file" name="file" id="file" />
<button id="upload">上传</button>
<span id="progress">0%</span>
var progress = document.querySelector('#progress');

// 点击上传
function uploadFile(event) {
 var formData = new FormData();
 formData.append('test-upload', file.files[0]);
 xhr.onload = uploadSuccess;
 xhr.upload.onprogress = setProgress;
 xhr.open('post', '/upload', true);
 xhr.send(formData);
}
// 进度条
function setProgress(event) {
 if (event.lengthComputable) {
 var complete = Number.parseInt(event.loaded / event.total * 100);
 progress.innerHTML = complete + '%';
 }
}

图片预览

上传图片的时候可以利用FileReader对象来实现图片预览。FileReader可以异步读取用户电脑上的文件,将file input选中的文件传给FileReader,读取之后取得文件的URL并设置为image元素的src即可让选中的图片文件显示出来。

<input type="file" name="file" id="file" />
<button id="upload">上传</button>
<span id="progress">0</span>
<img id="image" src="" width="200" />
var file = document.querySelector('#file');
file.addEventListener('change', previewImage, false);
// 图片预览
function previewImage(event) {
 var reader = new FileReader();
 reader.onload = function (event) {
 image.src = event.target.result;
 };
 reader.readAsDataURL(event.target.files[0]);
}

服务端处理

使用express搭建一个简单的NodeJS服务端,提供上传文件的接口。express要支持文件上传需要用到中间件,在express官网上有很多介绍。这里我使用的是multer中间件,下面是简单的使用示例。upload.single表示这个接口接受的上传文件数量为1个,'test-upload'限制了上传的表单数据的键为'test-upload'(formData.append(‘test-upload', file.files[0]);)。经过这个中间件处理之后,通过req.file可以访问到文件的相关信息,上传的文件存放在uploads文件夹中。

const upload = require('multer')({ dest: 'uploads/' });
app.post('/upload', upload.single('test-upload'), (req, res) => {
 // 没有附带文件
 if (!req.file) {
 res.json({ ok: false });
 return;
 }
 // 输出文件信息
 console.log('====================================================');
 console.log('fieldname: ' + req.file.fieldname);
 console.log('originalname: ' + req.file.originalname);
 console.log('encoding: ' + req.file.encoding);
 console.log('mimetype: ' + req.file.mimetype);
 console.log('size: ' + (req.file.size / 1024).toFixed(2) + 'KB');
 console.log('destination: ' + req.file.destination);
 console.log('filename: ' + req.file.filename);
 console.log('path: ' + req.file.path);
});

Ajax异步文件上传与NodeJS express服务端处理

由输出可以看到,文件的命名使用一个哈希值表示,并且去除了后缀名,想要保持文件的原有的命名格式,需要再通过fs对文件进行改名。

app.post('/upload', upload.single('test-upload'), (req, res) => {
 // 没有附带文件
 if (!req.file) {
 res.json({ ok: false });
 return;
 }

 // 输出文件信息
 console.log('====================================================');
 console.log('fieldname: ' + req.file.fieldname);
 console.log('originalname: ' + req.file.originalname);
 console.log('encoding: ' + req.file.encoding);
 console.log('mimetype: ' + req.file.mimetype);
 console.log('size: ' + (req.file.size / 1024).toFixed(2) + 'KB');
 console.log('destination: ' + req.file.destination);
 console.log('filename: ' + req.file.filename);
 console.log('path: ' + req.file.path);
 // 重命名文件
 let oldPath = path.join(__dirname, req.file.path);
 let newPath = path.join(__dirname, 'uploads/' + req.file.originalname);
 fs.rename(oldPath, newPath, (err) => {
 if (err) {
  res.json({ ok: false });
  console.log(err);
 } else {
  res.json({ ok: true });
 }
 });
});

完整代码

ajax异步文件上传、进度显示、图片预览

<input type="file" name="file" id="file" />
<button id="upload">上传</button>
<span id="progress">0</span>
<img id="image" src="" width="200" />
(function () {
 'use strict';

 var file = document.querySelector('#file');
 var upload = document.querySelector('#upload');
 var progress = document.querySelector('#progress');
 var image = document.querySelector('#image');
 var xhr = new XMLHttpRequest();

 upload.addEventListener('click', uploadFile, false);
 file.addEventListener('change', previewImage, false);

 // 点击上传
 function uploadFile(event) {
 var formData = new FormData();
 formData.append('test-upload', file.files[0]);
 xhr.onload = uploadSuccess;
 xhr.upload.onprogress = setProgress;
 xhr.open('post', '/upload', true);
 xhr.send(formData);
 }

 // 成功上传
 function uploadSuccess(event) {
 if (xhr.readyState === 4) {
  console.log(xhr.responseText);
 }
 }

 // 进度条
 function setProgress(event) {
 if (event.lengthComputable) {
  var complete = Number.parseInt(event.loaded / event.total * 100);
  progress.innerHTML = complete + '%';
 }
 }

 // 图片预览
 function previewImage(event) {
 var reader = new FileReader();
 reader.onload = function (event) {
  image.src = event.target.result;
 };
 reader.readAsDataURL(event.target.files[0]);
 }
})();

express服务器提供文件上传接口

const express = require('express');
const upload = require('multer')({ dest: 'uploads/' });
const path = require('path');
const fs = require('fs');
const port = 8080;

let app = express();

app.set('port', port);
// index.html, index.js放在static文件夹中
app.use(express.static(path.join(__dirname, 'static')));

app.get('*', (req, res) => {
 res.redirect('index.html');
});

app.post('/upload', upload.single('test-upload'), (req, res) => {
 // 没有附带文件
 if (!req.file) {
 res.json({ ok: false });
 return;
 }

 // 输出文件信息
 console.log('====================================================');
 console.log('fieldname: ' + req.file.fieldname);
 console.log('originalname: ' + req.file.originalname);
 console.log('encoding: ' + req.file.encoding);
 console.log('mimetype: ' + req.file.mimetype);
 console.log('size: ' + (req.file.size / 1024).toFixed(2) + 'KB');
 console.log('destination: ' + req.file.destination);
 console.log('filename: ' + req.file.filename);
 console.log('path: ' + req.file.path);

 // 重命名文件
 let oldPath = path.join(__dirname, req.file.path);
 let newPath = path.join(__dirname, 'uploads/' + req.file.originalname);
 fs.rename(oldPath, newPath, (err) => {
 if (err) {
  res.json({ ok: false });
  console.log(err);
 } else {
  res.json({ ok: true });
 }
 });
});
app.listen(port, () => {
 console.log("[Server] localhost:" + port);
});

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

NodeJs 相关文章推荐
PHPStorm 2020.1 调试 Nodejs的多种方法详解
Sep 17 NodeJs
在NodeJS中启用ECMAScript 6小结(windos以及Linux)
Jul 15 NodeJs
Nodejs实现多人同时在线移动鼠标的小游戏分享
Dec 06 NodeJs
NodeJS学习笔记之Http模块
Jan 13 NodeJs
学习 NodeJS 第八天:Socket 通讯实例
Dec 21 NodeJs
Express与NodeJs创建服务器的两种方法
Feb 06 NodeJs
搭建简单的nodejs http服务器详解
Mar 09 NodeJs
NodeJS实现微信公众号关注后自动回复功能
May 31 NodeJs
nodejs 生成和导出 word的实例代码
Jul 31 NodeJs
NodeJS如何实现同步的方法示例
Aug 24 NodeJs
nodejs 使用 js 模块的方法实例详解
Dec 04 NodeJs
浅谈使用nodejs搭建web服务器的过程
Jul 20 NodeJs
3分钟快速搭建nodejs本地服务器方法运行测试html/js
Apr 01 #NodeJs
nodejs使用express创建一个简单web应用
Mar 31 #NodeJs
nodejs实现邮件发送服务实例分享
Mar 29 #NodeJs
NodeJs测试框架Mocha的安装与使用
Mar 28 #NodeJs
NodeJS测试框架mocha入门教程
Mar 28 #NodeJs
nodejs模块nodemailer基本使用-邮件发送示例(支持附件)
Mar 28 #NodeJs
angular2+nodejs实现图片上传功能
Mar 27 #NodeJs
You might like
PHP 选项及相关信息函数库
2006/12/04 PHP
PHP设计模式之委托模式定义与用法简单示例
2018/08/13 PHP
php 实现简单的登录功能示例【基于thinkPHP框架】
2019/12/02 PHP
php 输出缓冲 Output Control用法实例详解
2020/03/03 PHP
PHP设计模式之 策略模式Strategy详解【对象行为型】
2020/05/01 PHP
jquery教程限制文本框只能输入数字和小数点示例分享
2014/01/13 Javascript
清除div下面的所有标签的方法
2014/02/17 Javascript
jquery中each方法示例和常用选择器
2014/07/08 Javascript
举例讲解jQuery中可见性过滤选择器的使用
2016/04/18 Javascript
JavaScript希尔排序、快速排序、归并排序算法
2016/05/08 Javascript
js获取对象、数组的实际长度,元素实际个数的实现代码
2016/06/08 Javascript
Vue.js动态组件解析
2016/09/09 Javascript
Java  Spring 事务回滚详解
2016/10/17 Javascript
angular4中关于表单的校验示例
2017/10/16 Javascript
BootStrap自定义popover,点击区域隐藏功能的实现
2018/01/23 Javascript
Vue服务器渲染Nuxt学习笔记
2018/01/31 Javascript
vue 项目地址去掉 #的方法
2018/10/20 Javascript
JS 验证码功能的三种实现方式
2018/11/26 Javascript
详解Vue-axios 设置请求头问题
2018/12/06 Javascript
JavaScript时间与时间戳的转换操作实例分析
2018/12/07 Javascript
js常见遍历操作小结
2019/06/06 Javascript
Vue Element UI + OSS实现上传文件功能
2019/07/31 Javascript
vue图片加载失败时用默认图片替换的方法
2019/08/29 Javascript
ES6中Promise的使用方法实例总结
2020/02/18 Javascript
antd多选下拉框一行展示的实现方式
2020/10/31 Javascript
Python实现两款计算器功能示例
2017/12/19 Python
Python反射和内置方法重写操作详解
2018/08/27 Python
python 命名规范知识点汇总
2020/02/14 Python
pycharm + django跨域无提示的解决方法
2020/12/06 Python
Python制作简单的剪刀石头布游戏
2020/12/10 Python
用CSS3实现瀑布流布局的示例代码
2017/11/10 HTML / CSS
探究 canvas 绘图中撤销(undo)功能的实现方式详解
2018/05/17 HTML / CSS
在C语言中实现抽象数据类型什么方法最好
2014/06/26 面试题
大学生毕业自我鉴定
2013/11/06 职场文书
苦儿流浪记读书笔记
2015/07/01 职场文书
解决flex布局中子项目尺寸不受flex-shrink限制
2022/05/11 HTML / CSS