在前端开发中,文件上传是一个常见的需求。但是,传统的文件上传方式会让用户等待上传过程完成,体验不佳。而使用 Server-Sent Events 技术,可以实现异步文件上传的服务器端处理,让用户可以在上传过程中继续浏览其他页面,提高用户体验。
Server-Sent Events 简介
Server-Sent Events 是一种 HTML5 新增的技术,可以让服务器端向客户端推送事件。与 WebSocket 不同,Server-Sent Events 是基于 HTTP 协议的单向通信,只能由服务器端向客户端发送数据,而不能由客户端向服务器端发送数据。
实现异步文件上传的服务器端处理
使用 Server-Sent Events 实现异步文件上传的服务器端处理,需要以下步骤:
- 客户端使用 FormData 对象上传文件,并将上传进度通过 Server-Sent Events 推送给服务器端。
- 服务器端接收到文件上传请求后,将文件保存到指定的位置,并将上传进度通过 Server-Sent Events 推送给客户端。
下面是一个使用 Node.js 实现异步文件上传的服务器端处理的示例代码:
// www.javascriptcn.com code example
const http = require('http');
const fs = require('fs');
const path = require('path');
http.createServer(function(req, res) {
if (req.url === '/upload' && req.method === 'POST') {
const form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
const file = files.file;
const filePath = path.join(__dirname, 'uploads', file.name);
const readStream = fs.createReadStream(file.path);
const writeStream = fs.createWriteStream(filePath);
let uploadedBytes = 0;
readStream.on('data', function(chunk) {
uploadedBytes += chunk.length;
const progress = parseInt((uploadedBytes / file.size) * 100);
res.write(`event: progress\ndata: ${progress}\n\n`);
});
readStream.on('end', function() {
res.write(`event: complete\ndata: ${filePath}\n\n`);
res.end();
});
readStream.pipe(writeStream);
});
} else {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(`
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="Upload">
</form>
<script>
const source = new EventSource('/progress');
source.addEventListener('progress', function(event) {
const progress = event.data;
console.log(progress);
});
source.addEventListener('complete', function(event) {
const filePath = event.data;
console.log(filePath);
});
</script>
`);
}
}).listen(3000);客户端使用 FormData 对象上传文件,并通过 Server-Sent Events 推送上传进度:
// www.javascriptcn.com code example
const form = document.querySelector('form');
form.addEventListener('submit', function(event) {
event.preventDefault();
const file = form.querySelector('input[type="file"]').files[0];
const xhr = new XMLHttpRequest();
xhr.open('POST', '/upload');
xhr.setRequestHeader('Content-Type', 'multipart/form-data');
xhr.onreadystatechange = function() {
if (xhr.readyState === 3 && xhr.status === 200) {
const progress = xhr.responseText;
const eventSource = new EventSource('/progress');
eventSource.addEventListener('progress', function(event) {
const percentComplete = parseInt(event.data);
console.log(percentComplete);
});
eventSource.addEventListener('complete', function(event) {
const filePath = event.data;
console.log(filePath);
});
}
};
const formData = new FormData();
formData.append('file', file);
xhr.send(formData);
});服务器端接收到文件上传请求后,将文件保存到指定的位置,并通过 Server-Sent Events 推送上传进度:
// www.javascriptcn.com code example
const http = require('http');
const formidable = require('formidable');
const fs = require('fs');
const path = require('path');
http.createServer(function(req, res) {
if (req.url === '/upload' && req.method === 'POST') {
const form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
const file = files.file;
const filePath = path.join(__dirname, 'uploads', file.name);
const readStream = fs.createReadStream(file.path);
const writeStream = fs.createWriteStream(filePath);
let uploadedBytes = 0;
readStream.on('data', function(chunk) {
uploadedBytes += chunk.length;
const progress = parseInt((uploadedBytes / file.size) * 100);
res.write(`event: progress\ndata: ${progress}\n\n`);
});
readStream.on('end', function() {
res.write(`event: complete\ndata: ${filePath}\n\n`);
res.end();
});
readStream.pipe(writeStream);
});
} else {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(`
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="Upload">
</form>
<script>
const source = new EventSource('/progress');
source.addEventListener('progress', function(event) {
const progress = event.data;
console.log(progress);
});
source.addEventListener('complete', function(event) {
const filePath = event.data;
console.log(filePath);
});
</script>
`);
}
}).listen(3000);学习和指导意义
使用 Server-Sent Events 实现异步文件上传的服务器端处理,可以提高用户体验,让用户可以在上传过程中继续浏览其他页面。同时,这种技术也适用于其他需要长时间处理的任务,比如视频转码、图像处理等。
在实现过程中,需要注意以下几点:
- Server-Sent Events 是基于 HTTP 协议的单向通信,只能由服务器端向客户端发送数据,而不能由客户端向服务器端发送数据。
- 在客户端使用 Server-Sent Events 接收事件时,需要注意浏览器的兼容性问题。
- 在服务器端推送事件时,需要注意事件类型的命名规范,以便客户端能够正确接收事件。
通过学习和掌握 Server-Sent Events 技术,可以提高前端开发的技能和水平,为用户提供更好的体验。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67d430d4a941bf71347e5d40