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 相关文章推荐
使用Nodejs开发微信公众号后台服务实例
Sep 03 NodeJs
Nodejs实现的一个简单udp广播服务器、客户端
Sep 25 NodeJs
Nodejs实现批量下载妹纸图
May 28 NodeJs
Nodejs的express使用教程
Nov 23 NodeJs
3分钟快速搭建nodejs本地服务器方法运行测试html/js
Apr 01 NodeJs
nodejs个人博客开发第三步 载入页面
Apr 12 NodeJs
深入理解Nodejs Global 模块
Jun 03 NodeJs
浅析 NodeJs 的几种文件路径
Jun 07 NodeJs
nodejs Assert中equal(),strictEqual(),deepEqual(),strictDeepEqual()比较
Sep 18 NodeJs
Mac 安装 nodejs方法(图文详细步骤)
Oct 30 NodeJs
修改Nodejs内置的npm默认配置路径方法
May 13 NodeJs
NodeJS实现同步的方法
Mar 02 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/10/09 PHP
Javascript 函数中的参数使用分析
2010/03/27 Javascript
jQuery学习笔记之Helloworld
2010/12/22 Javascript
js中将HTMLCollection/NodeList/伪数组转换成数组的代码
2011/07/31 Javascript
javascript数组操作(创建、元素删除、数组的拷贝)
2014/04/07 Javascript
页面刷新时记住滚动条的位置jquery代码
2014/06/17 Javascript
jquery基础知识第一讲之认识jquery
2016/03/17 Javascript
浅谈javascript控制HTML5的全屏操控,浏览器兼容的问题
2016/10/10 Javascript
Vue系列:通过vue-router如何传递参数示例
2017/01/16 Javascript
基于JS脚本语言的基础语法详解
2017/07/22 Javascript
node.js实现微信JS-API封装接口的示例代码
2017/09/06 Javascript
深入理解Node.js中通用基础设计模式
2017/09/19 Javascript
vue实现样式之间的切换及vue动态样式的实现方法
2017/12/19 Javascript
每天学点Vue源码之vm.$mount挂载函数
2019/03/11 Javascript
Node.js中Koa2在控制台输出请求日志的方法示例
2019/05/02 Javascript
Vue 列表上下过渡效果的实例代码
2019/06/25 Javascript
微信小程序如何自定义table组件
2019/06/29 Javascript
vue拖拽组件 vuedraggable API options实现盒子之间相互拖拽排序
2019/07/08 Javascript
Vue+elementui 实现复杂表头和动态增加列的二维表格功能
2019/09/23 Javascript
node读写Excel操作实例分析
2019/11/06 Javascript
[01:14]3.19DOTA2发布会 三代刀塔人第二代
2014/03/25 DOTA
Python模块学习 re 正则表达式
2011/05/19 Python
python二叉树的实现实例
2013/11/21 Python
python合并已经存在的sheet数据到新sheet的方法
2018/12/11 Python
pytorch对梯度进行可视化进行梯度检查教程
2020/02/04 Python
pycharm 激活码及使用方式的详细教程
2020/05/12 Python
如何将anaconda安装配置的mmdetection环境离线拷贝到另一台电脑
2020/10/15 Python
全球领先美式家具品牌:Ashley爱室丽家居
2017/08/07 全球购物
英国50岁以上人群的交友网站:Ourtime
2018/03/28 全球购物
lululemon美国官网:瑜伽服+跑步装备
2018/11/16 全球购物
您附近的水疗和健康场所:Spafinder(美国)
2019/07/05 全球购物
教师业务学习制度
2014/01/25 职场文书
少儿节目主持串词
2014/04/02 职场文书
2014年团工作总结
2014/11/27 职场文书
Python爬虫之自动爬取某车之家各车销售数据
2021/06/02 Python
JavaScript 对象创建的3种方法
2021/11/17 Javascript