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

发布时间 - 2026-01-11 00:28:57    点击率:

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

文件上传

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);
});

由输出可以看到,文件的命名使用一个哈希值表示,并且去除了后缀名,想要保持文件的原有的命名格式,需要再通过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);
});

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


# ajax异步上传文件  # nodejs  # express  # 异步  # node+axios实现服务端文件上传示例  # 利用node+koa+axios实现图片上传和回显功能  # 详解Vue+axios+Node+express实现文件上传(用户头像上传)  # nodejs+express实现文件上传下载管理网站  # nodejs基于express实现文件上传的方法  # 详解nodejs实现本地上传图片并预览功能(express4.0+)  # Nodejs+express+html5 实现拖拽上传  # 基于nodejs+express(4.x+)实现文件上传功能  # 使用express+multer实现node中的图片上传功能  # 使用nodejs+express实现简单的文件上传功能  # Nodejs进阶:基于express+multer的文件上传实例  # NodeJS实现图片上传代码(Express)  # node+express+axios实现单文件上传功能  # 上传  # 文件上传  # 进度条  # 表单  # 放在  # 来实现  # 服务端  # 上传文件  # 重命名  # 的是  # 是在  # 会有  # 夹中  # 上有  # 看了看  # 可以看到  # 相关信息  # 还需要  # 等功能  # 提供一个 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: Laravel怎么实现模型属性转换Casting_Laravel自动将JSON字段转为数组【技巧】  如何获取免费开源的自助建站系统源码?  Swift中循环语句中的转移语句 break 和 continue  如何在IIS中新建站点并配置端口与物理路径?  实例解析angularjs的filter过滤器  谷歌Google入口永久地址_Google搜索引擎官网首页永久入口  大连网站制作费用,大连新青年网站,五年四班里的视频怎样下载啊?  如何在阿里云域名上完成建站全流程?  音乐网站服务器如何优化API响应速度?  Win11怎么开启自动HDR画质_Windows11显示设置HDR选项  Laravel怎么配置自定义表前缀_Laravel数据库迁移与Eloquent表名映射【步骤】  高端建站如何打造兼具美学与转化的品牌官网?  Python自然语言搜索引擎项目教程_倒排索引查询优化案例  千问怎样用提示词获取健康建议_千问健康类提示词注意事项【指南】  bootstrap日历插件datetimepicker使用方法  JS中页面与页面之间超链接跳转中文乱码问题的解决办法  Laravel如何使用Service Container和依赖注入?(代码示例)  Laravel如何实现URL美化Slug功能_Laravel使用eloquent-sluggable生成别名【方法】  laravel怎么为应用开启和关闭维护模式_laravel应用维护模式开启与关闭方法  ,南京靠谱的征婚网站?  javascript中闭包概念与用法深入理解  如何快速生成可下载的建站源码工具?  如何在香港免费服务器上快速搭建网站?  Android okhttputils现在进度显示实例代码  Python进程池调度策略_任务分发说明【指导】  Laravel中Service Container是做什么的_Laravel服务容器与依赖注入核心概念解析  Java遍历集合的三种方式  html如何与html链接_实现多个HTML页面互相链接【互相】  详解免费开源的DotNet二维码操作组件ThoughtWorks.QRCode(.NET组件介绍之四)  Laravel如何使用Livewire构建动态组件?(入门代码)  详解一款开源免费的.NET文档操作组件DocX(.NET组件介绍之一)  大型企业网站制作流程,做网站需要注册公司吗?  Laravel如何处理异常和错误?(Handler示例)  Laravel如何使用Gate和Policy进行权限控制_Laravel权限判定与策略规则配置  如何在阿里云香港服务器快速搭建网站?  Angular 表单中正确绑定输入值以确保提交与验证正常工作  javascript中的try catch异常捕获机制用法分析  Laravel如何使用缓存系统提升性能_Laravel缓存驱动和应用优化方案  如何在阿里云虚拟服务器快速搭建网站?  如何挑选优质建站一级代理提升网站排名?  如何挑选最适合建站的高性能VPS主机?  Python并发异常传播_错误处理解析【教程】  Python结构化数据采集_字段抽取解析【教程】  HTML5空格和margin有啥区别_空格与外边距的使用场景【说明】  SQL查询语句优化的实用方法总结  Python面向对象测试方法_mock解析【教程】  Python自动化办公教程_ExcelWordPDF批量处理案例  韩国网站服务器搭建指南:VPS选购、域名解析与DNS配置推荐  今日头条微视频如何找选题 今日头条微视频找选题技巧【指南】  Laravel如何实现多语言支持_Laravel本地化与国际化(i18n)配置教程