首页 > 其他分享 >ajax上传、下载文件

ajax上传、下载文件

时间:2024-11-06 22:19:41浏览次数:1  
标签:文件 const xhr ajax file 分片 上传 下载

一、上传

1.上传数据的封装

在上传文件时,最常用的方式是使用 FormData 对象,它会自动将请求头中的 Content-Type 请求头指定为multipart/form-data

const formData = new FormData();
formData.append("file", fileInput.files[0]);  // fileInput 是 <input type="file">

const xhr = new XMLHttpRequest();
xhr.open("POST", "/upload");

// 不要设置 Content-Type,浏览器会自动生成类似于 multipart/form-data 的头
xhr.send(formData);

2.上传进度条

XMLHttpRequest 对象的 upload 属性有一个 progress 事件,它可以获取文件上传的进度。每当文件上传进度更新时,都会触发该事件,提供已上传字节数和文件总大小的信息

    const xhr = new XMLHttpRequest();
    xhr.open("POST", "/upload");  // 替换为实际的上传 URL
    // 监听上传进度事件
    xhr.upload.addEventListener("progress", (event) => {
      if (event.lengthComputable) {
        const percentComplete = (event.loaded / event.total) * 100;
        const progressBar = document.getElementById("progress-bar");
        progressBar.style.width = percentComplete + "%";
        progressBar.textContent = Math.round(percentComplete) + "%";
      }
    });
    // 上传完成事件
    xhr.onload = () => {
      if (xhr.status === 200) {
        alert("上传成功!");
      } else {
        alert("上传失败!");
      }
    };
    // 发送表单数据
    xhr.send(formData);

3.大文件上传

文件分片上传的关键技术主要涉及文件分片、分片上传、分片管理和服务器端的分片合并。这些技术通过优化传输和可靠性,确保大文件在网络不稳定或需要续传的场景下能够顺利完成上传。以下是文件分片上传的关键技术点:

文件分片(Chunking)

  • 技术点:文件分片是将大文件按固定大小(通常为 1 MB 或 5 MB)划分为若干小块(Chunk),这些分片可以单独处理和上传。通过 JavaScript 的 Blob.slice 方法可以轻松实现分片。
  • 实现细节:在前端使用 Blob.slice(start, end) 方法获取每个分片,通过循环逐片读取并存储到 FormData 中。

分片上传与进度管理

  • 技术点:每个分片单独发起上传请求(如使用 XMLHttpRequestfetch),通过监听上传进度事件来实时更新上传进度。同时,可以记录每个分片的状态,便于上传失败时进行重试。
  • 并发上传:对于大文件,可以并发上传多个分片(Promise.all),提高上传速度。例如,前端可以控制同时上传 3 个分片,并在其中一个分片完成后再上传下一个分片。
  • 并发控制:通过控制并发数,既保证上传速度,又防止过多并发导致服务器压力过大。

分片标识与校验

  • 分片标识:每个分片通常使用唯一标识(如文件名、分片序号、总分片数)来标识,可以在请求中带上这些信息,方便服务器识别每个分片的位置。
  • 分片校验:为了确保每个分片正确上传,可以对每个分片计算哈希值(如 MD5、SHA-256),服务器上传后进行校验。这样可以在上传失败或分片出错时重试,保证数据完整性。

服务端分片接收与校验

  • 接收分片:服务器根据上传请求中的分片标识(如 chunkIndextotalChunks)存储每个分片,通常放在临时文件夹中。
  • 校验分片:每个分片上传后可以计算哈希并与客户端传来的哈希比对,确保分片未损坏。校验通过后才认为分片上传成功,失败则需要重新上传该分片。

服务端合并分片

  • 合并触发:在服务器端收到所有分片后,可以触发文件合并。通常通过 chunkIndextotalChunks 判断是否收到完整文件。
  • 合并顺序:合并时需要按照 chunkIndex 顺序将所有分片按序读入并写入完整文件。
  • 并发与异步:合并过程可以使用多线程或异步方法,尤其是当文件较大时,可以提升合并效率。
  • 清理临时文件:合并完成后需要删除分片的临时文件,释放服务器存储空间。

断点续传支持

  • 断点记录:断点续传的关键在于记录已上传的分片。前端可以在本地存储(如 localStorage)中记录已成功上传的分片序号。
  • 续传实现:当上传中断时,用户可以从记录的进度重新开始上传,无需重复上传已完成的分片。这可以减少带宽浪费和上传时间。

7.实现代码

客户端

  const CHUNK_SIZE = 1024 * 1024; // 每片1MB
  async function uploadFile() {
    const fileInput = document.getElementById("fileInput");
    const file = fileInput.files[0];
    if (!file) {
      alert("请选择文件后再上传!");
      return;
    }

    const totalChunks = Math.ceil(file.size / CHUNK_SIZE);  // 计算分片数量
    let uploadedChunks = 0;

    for (let start = 0; start < file.size; start += CHUNK_SIZE) {
      const end = Math.min(start + CHUNK_SIZE, file.size);
      const chunk = file.slice(start, end); // 获取文件分片
      const chunkIndex = start / CHUNK_SIZE; // 当前分片序号

      // 使用 FormData 上传每个分片
      const formData = new FormData();
      formData.append("file", chunk); // 添加分片数据
      formData.append("filename", file.name); // 添加文件名
      formData.append("chunkIndex", chunkIndex); // 添加分片序号
      formData.append("totalChunks", totalChunks); // 添加总分片数

      // 上传当前分片
      try {
//等待当前task完成后再进入下一个循环 await uploadChunk(formData); uploadedChunks++; updateProgress(uploadedChunks, totalChunks); // 更新进度条 } catch (error) { console.error(`分片 ${chunkIndex} 上传失败`, error); return; // 上传失败退出 } } alert("文件上传成功!"); } function uploadChunk(formData) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open("POST", "/upload-chunk"); // 替换为实际的上传 URL xhr.onload = () => { if (xhr.status === 200) { resolve(); } else { reject(new Error("分片上传失败")); } }; xhr.onerror = () => reject(new Error("网络错误")); xhr.send(formData); }); } // 更新进度条 function updateProgress(uploadedChunks, totalChunks) { const progressBar = document.getElementById("progress-bar"); const percentComplete = (uploadedChunks / totalChunks) * 100; progressBar.textContent = `上传进度: ${Math.round(percentComplete)}%`; } 

服务端

在所有分片上传完毕后,服务器端会收到所有分片并合并。服务器可以根据 filenamechunkIndex 来识别每个分片,并按顺序合并它们。

 

const fs = require("fs");
const path = require("path");
const express = require("express");
const app = express();
const uploadDir = "uploads/"; // 保存分片的临时目录

app.post("/upload-chunk", (req, res) => {
  const { filename, chunkIndex, totalChunks } = req.body;
  const chunk = req.files.file; // 获取上传的分片文件

  // 将每个分片存储到临时文件夹
  const chunkPath = path.join(uploadDir, `${filename}.part${chunkIndex}`);
  fs.writeFileSync(chunkPath, chunk.data);

  // 检查是否所有分片都上传完成
  if (parseInt(chunkIndex) === totalChunks - 1) {
    // 合并所有分片
    const filePath = path.join(uploadDir, filename);
    const writeStream = fs.createWriteStream(filePath);

    for (let i = 0; i < totalChunks; i++) {
      const partPath = path.join(uploadDir, `${filename}.part${i}`);
      const data = fs.readFileSync(partPath);
      writeStream.write(data);
      fs.unlinkSync(partPath); // 删除已合并的分片
    }

    writeStream.end();
    res.send("文件上传成功并合并完成!");
  } else {
    res.send("分片上传成功!");
  }
});

app.listen(3000, () => {
  console.log("Server started on http://localhost:3000");
});

 

二、下载

1. 使用 <a> 标签的 download 属性

这是实现文件下载最简单的方式。<a> 标签的 download 属性可以强制浏览器下载文件而不是直接打开文件。

<a href="path/to/file.pdf" download="filename.pdf">下载文件</a>
当需要下载的数据是由 JavaScript 动态生成时,可以将数据转换为 Blob 对象,并生成一个 URL 来进行下载。使用 Blob 和 URL.createObjectURL 生成下载链接
function downloadBlob(data, filename, mimeType) {
  const blob = new Blob([data], { type: mimeType });
  const url = URL.createObjectURL(blob);

  const a = document.createElement("a");
  a.href = url;
  a.download = filename;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);

  URL.revokeObjectURL(url); // 释放 URL
}

// 使用示例
const data = "Hello, this is a text file!";
downloadBlob(data, "example.txt", "text/plain");

2.使用ajax和 Blob 实现文件下载

不推荐使用该方法。下载速度比方法1要慢,要等ajax接收完文件再调用浏览器的文件保存api,文件较大时点击后可能需要很长时间才有反应,并且下载传输过程中出现问题后,无法断点续传。

async function downloadFile(url, filename) {
  const response = await fetch(url);
  const blob = await response.blob();

  const a = document.createElement("a");
  a.href = URL.createObjectURL(blob);
  a.download = filename;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);

  URL.revokeObjectURL(a.href);
}

// 使用示例
downloadFile("path/to/file.pdf", "downloaded_file.pdf");

  

 

标签:文件,const,xhr,ajax,file,分片,上传,下载
From: https://www.cnblogs.com/94pm/p/18531157

相关文章

  • 有道领世视频课程下载工具,如何在电脑端下载有道领世视频课程到本地?
    一.安装有道领世课程下载器1.获取学无止下载器https://www.xuewuzhi.cn/ydshengxue_downloader2.下载安装后,然后点击桌面快捷方式运行即可。注意:杀毒软件可能会阻止外部exe文件运行,并将其当做成病毒,直接添加信任即可,本软件绝对没有木马病毒。二.使用说明1.学无止下载器介......
  • 【Tableau2023软件下载与安装教程】
    Tableau2023‌是一款强大的数据可视化和数据分析软件,广泛应用于商业智能领域。它通过提供直观的界面和丰富的数据分析功能,使用户能够轻松地从复杂的数据中提取见解和策略,从而加速数据分析和报告生成的过程‌。1、安装包  Tableau2023:链接:https://pan.quark.cn/s/195fd628......
  • python webdriver-manager 实现selenium 免下载安装webdriver
    selenium在自动化测试中,通常需要使用浏览器驱动来与浏览器进行交互。然而,手动下载、安装、以及管理这些驱动非常麻烦,尤其是当驱动版本频繁更新时。为此,webdriver-manager库提供了一个极简的方案,自动帮我们下载、更新和管理驱动,使Selenium代码更简洁优雅。webdriver-managergit......
  • 微信公众号音频下载器
    我关注的一个大V,总是喜欢发布音频内容。但是呢,由于众所周知的原因,这些内容往往被删除了,我就没法再听了。。。于是,我想给他的音频保存下来。虽然我可以自己搞定,但是毕竟没有现成的工具。于是,我发挥程序员的优势,自己动手写一个小工具。于是,就有了微信公众号音频下载器这个工具。......
  • [Uniapp] APP拍照后转换Base64上传
    组件(2选1):1.uni-file-picker:https://uniapp.dcloud.net.cn/component/uniui/uni-file-picker.html2.u-upload: https://uviewui.com/components/upload.html 思路:不想直接把图片存到数据库,因为想着图片是小文件,也不是重要文件,干脆存到数据库里就好了。因此,计划在前端......
  • GEE学习part5—图表函数与图表数据下载
    代码://方法三:GEE将计算公式封装为一个方法可以直接调用functionNDVI_V3(img){varndvi=img.normalizedDifference(["B8","B4"]);returnndvi;}//sentinel2androivars2_col=ee.ImageCollection("COPERNICUS/S2");varroi=ee.Geometry.Point([1......
  • 第20章 SpringBoot上传文件
    在SpringBoot中实现文件上传仍然使用SpringMVC的MultipartFile类来处理。我们创建一个“SpringBootUploadDemo”的工程然后我们修改编码格式以及Maven仓库地址,我们省略这个过程了。接下来,我们修改“pom.xml”文件,添加SpringBoot和Web依赖,如下所示<?xmlversion="1.0......
  • 网站上传修改数据库,通过FTP和后台管理修改数据库的步骤
    一、通过FTP上传数据库文件备份现有数据库在进行任何操作之前,首先备份现有的数据库。可以通过phpMyAdmin或其他数据库管理工具导出数据库文件。准备新的数据库文件准备好新的数据库文件(通常为SQL文件),确保文件内容正确无误。连接到FTP服务器使用FTP客户端连接到你......
  • Typora配置图片上传功能:gitee码云+Picgo
    Typora配置图片上传功能:gitee码云+Picgo下载Picgo:官方在github上可以直接下载:链接在gitee上配置自己的仓库:Picgo的配置:首先打开picgo选择图床设置里的gitee然后设置自己的路径和名称:图床配置名随便起repo就是路径branch写自己的分支,我写的是masterpa......
  • Ollama简介,以及中文使用指南和AMD图形显卡驱动下载
    Ollama是一个开源的大型语言模型(LLM)服务工具,它旨在简化在本地运行大语言模型的过程,降低使用大语言模型的门槛。Ollama使得开发者、研究人员和爱好者能够在本地环境快速实验、管理和部署最新的大语言模型,包括但不限于如Qwen2、Llama3、Phi3、Gemma2等开源的大型语言模型。Oll......