1.API说明
在html中可以使用XMLHttpRequest和FormData来实现文件上传功能
XMLHttpRequest:是一种 JavaScript API,它提供了在浏览器和服务器之间传输数据的功能,而不需要刷新整个页面,这个 API 使得网页能够异步地在后台发送和接收数据,支持多种 HTTP 方法,如GET、POST。在这里实现文件的上传操作。
FormData:是一个 JavaScript 对象,用于构建一组键值对,用于模拟 HTML 表单数据,方便地将数据发送到服务器。它可以包含多种类型的数据,包括文件数据。
2.实现文件分块上传示例
许多服务器和网络环境对上传文件的大小有限制。例如,一些服务器默认设置单次上传文件大小不能超过几兆字节(如 2MB 或 5MB)。通过分块上传,可以将大文件拆分成多个较小的块,每个块的大小在服务器允许的范围内,这样就能绕过这种限制,成功上传大文件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文件分块上传示例</title>
</head>
<body>
<input type="file" id="fileUpload" multiple>
<progress id="uploadProgress" value="0" max="100"></progress>
<button id="uploadButton">上传文件</button>
<!--
1.创建了一个file文件输入框,其中multiple属性允许用户选择多个文件进行上传。
2.创建了一个progress元素,用于展示文件上传的进度,初始值设为 0,最大值设为 100。
3.创建一个button上传按钮,点击该按钮来触发文件上传操作。
-->
</body>
<script>
//获取 HTML 页面中的文件输入框、进度条和上传按钮的引用,以便后续操作。
const fileUpload = document.getElementById('fileUpload');
const uploadProgress = document.getElementById('uploadProgress');
const uploadButton = document.getElementById('uploadButton');
//定义了CHUNK_SIZE常量,用于设置文件分块的大小,这里设为 1MB(1024 * 1024字节)。
const CHUNK_SIZE = 1024 * 1024;
//给上传按钮添加点击事件监听器
uploadButton.addEventListener('click', function () {
const files = fileUpload.files;
//检查是否选择了文件,若未选择则弹出提示框告知用户并终止操作
if (files.length === 0) {
alert('请选择要上传的文件');
return;
}
//这里先假设只上传单个文件,如需上传多个可进行循环处理
const file = files[0];
//offset用于记录当前已上传的字节偏移量,初始为 0;
//totalChunks通过文件总大小除以分块大小并向上取整得到文件总共要分成的块数;
//uploadedChunks用于记录已经上传成功的块数,初始为 0。
let offset = 0;
const totalChunks = Math.ceil(file.size / CHUNK_SIZE);
let uploadedChunks = 0;
//定义uploadChunk函数用于上传单个分块
function uploadChunk() {
const chunkEnd = Math.min(offset + CHUNK_SIZE, file.size);
const chunk = file.slice(offset, chunkEnd);
const formData = new FormData();
formData.append('chunk', chunk);
formData.append('filename', file.name);
formData.append('totalChunks', totalChunks);
formData.append('uploadedChunks', uploadedChunks);
const xhr = new XMLHttpRequest();
xhr.open('POST', 'your_upload_url_here', true);
xhr.upload.onprogress = function (e) {
if (e.lengthComputable) {
const percentComplete = ((uploadedChunks * CHUNK_SIZE + e.loaded) / file.size) * 100;
uploadProgress.value = percentComplete;
}
};
xhr.onload = function () {
if (xhr.status === 200) {
uploadedChunks++;
if (uploadedChunks < totalChunks) {
offset += CHUNK_SIZE;
//采用递归调用的方式,继续调用uploadChunk函数上传下一个块
uploadChunk();
} else {
alert('文件上传成功');
}
} else {
alert('文件上传失败:' + xhr.statusText);
}
};
xhr.send(formData);
}
//调用uploadChunk函数开始上传第一个分块
uploadChunk();
});
</script>
</html>
uploadChunk函数说明:
1.根据当前offset和分块大小确定当前分块的结束位置chunkEnd,然后通过file.slice方法从文件中截取当前分块数据。
2.创建FormData对象,将分块数据、文件名、总块数、已上传块数等信息添加到FormData中,以便服务器端能正确处理和识别。
3.创建XMLHttpRequest对象并设置请求方式为POST,指定上传的服务器端 URL(需替换为实际地址)。
4.监听xhr.upload的onprogress事件,在上传分块过程中有数据传输时触发。如果上传字节长度可计算,通过已上传块数乘以分块大小加上当前分块已上传字节数与文件总大小的比例乘以 100 来计算上传进度百分比,并更新进度条的value属性。
5.监听xhr的onload事件,当分块上传完成后,如果服务器返回状态码为 200,说明当前分块上传成功,uploadedChunks加 1。若还有未上传的块数,更新offset为下一个分块的起始位置并再次调用uploadChunk函数继续上传下一个分块;
若所有块都已上传完,则弹出提示框告知用户文件上传成功。若服务器返回状态不是 200,则弹出提示框告知用户文件上传失败及原因。
3.上传数据报文分析
示例html效果图:
下面是使用360浏览器,截取报文截图 :
1.文件数据(二进制),这里作为示例,文件总长度只有几十个字节
2.文件名称(filename):test.txt
3.总的文件块数(totoalChunks): 1
4.已上传的块(uploadedChunks):也是当前块序号,第一块的序号是“0“;
上述代码中的服务器端接收上传文件的 URL 需要根据实际情况进行替换和配置,并且服务器端也需要相应的代码来正确处理接收到的分块上传文件信息,比如要能识别和拼接分块还原成完整文件等操作。