最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

React+Node.js實(shí)現(xiàn)大文件傳輸與斷點(diǎn)續(xù)傳

 更新時(shí)間:2024年12月20日 08:42:30   作者:走,板磚去  
這篇文章主要為大家詳細(xì)介紹了如何使用React前端和Node.js后端實(shí)現(xiàn)大文件傳輸和斷點(diǎn)續(xù)傳的功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以參考下

簡(jiǎn)述

使用React前端和Node.js后端實(shí)現(xiàn)大文件傳輸和斷點(diǎn)續(xù)傳的功能。通過(guò)分片上傳技術(shù),可以有效地解決網(wǎng)絡(luò)不穩(wěn)定帶來(lái)的傳輸中斷問(wèn)題。

前端實(shí)現(xiàn)(React)

首先,您需要在前端項(xiàng)目中安裝axios、spark-md5庫(kù)以處理HTTP請(qǐng)求??梢允褂靡韵旅睿?/p>

npm i axios spark-md5

以下是實(shí)現(xiàn)大文件上傳的React組件代碼:

import axios from 'axios';
import { useRef, useState } from 'react';

// 定義文件分片大?。ɡ?5MB)
const CHUNK_SIZE = 5 * 1024 * 1024;

/** 解析當(dāng)前頁(yè)面功能 */
export default function FileUploader() {
  const [file, setFile] = useState(null); // 用于存儲(chǔ)用戶(hù)選擇的文件
  const [uploadProgress, setUploadProgress] = useState(0); // 上傳進(jìn)度
  const uploading = useRef(false); // 用于防止重復(fù)觸發(fā)上傳邏輯

  // 當(dāng)用戶(hù)選擇文件時(shí)觸發(fā)
  const handleFileChange = (e) => {
    setFile(e.target.files[0]); // 將選擇的文件存入狀態(tài)
    setUploadProgress(0); // 重置上傳進(jìn)度
  };

  // 計(jì)算文件的唯一標(biāo)識(shí) (哈希)
  const calculateFileHash = async (file) => {
    return new Promise((resolve) => {
      const reader = new FileReader();
      reader.onload = (e) => {
        const sparkMD5 = require('spark-md5');
        const hash = sparkMD5.ArrayBuffer.hash(e.target.result);
        resolve(hash);
      };
      reader.readAsArrayBuffer(file);
    });
  };

  // 開(kāi)始文件上傳
  const handleUpload = async () => {
    if (!file || uploading.current) return; // 如果未選擇文件或正在上傳,則直接返回

    uploading.current = true; // 標(biāo)記為正在上傳
    const fileHash = await calculateFileHash(file); // 獲取文件的唯一標(biāo)識(shí)(哈希值)
    console.log('fileHash', fileHash);
    const totalChunks = Math.ceil(file.size / CHUNK_SIZE); // 計(jì)算文件分片總數(shù)
    // 檢查哪些分片已經(jīng)上傳
    const { data: uploadedChunks } = await axios.post(
      'http://localhost:5000/check',
      {
        fileName: file.name,
        fileHash,
      },
    );

    // 上傳未完成的分片
    for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
      if (uploadedChunks?.includes(chunkIndex)) {
        console.log('跳過(guò)chunkIndx', chunkIndex);
        setUploadProgress(((chunkIndex + 1) / totalChunks) * 100); // 更新進(jìn)度
        continue; // 跳過(guò)已經(jīng)上傳的分片
      }
      console.log('上傳chunkIndx', chunkIndex);
      // 創(chuàng)建當(dāng)前分片
      const start = chunkIndex * CHUNK_SIZE; // 分片起始字節(jié)
      const end = Math.min(file.size, start + CHUNK_SIZE); // 分片結(jié)束字節(jié)
      const chunk = file.slice(start, end); // 獲取分片

      // 上傳分片
      const formData = new FormData();
      formData.append('chunk', chunk); // 當(dāng)前分片
      formData.append('fileName', file.name); // 文件名
      formData.append('fileHash', fileHash); // 文件唯一標(biāo)識(shí)
      formData.append('chunkIndex', chunkIndex); // 分片索引

      await axios.post(
        `http://localhost:5000/upload?fileHash=${fileHash}&chunkIndex=${chunkIndex}&fileName=${file.name}`,
        formData,
        {
          onUploadProgress: (progressEvent) => {
            const progress =
              ((chunkIndex + progressEvent.loaded / progressEvent.total) /
                totalChunks) *
              100;
            setUploadProgress(progress); // 實(shí)時(shí)更新上傳進(jìn)度
          },
        },
      );
    }

    // 通知服務(wù)端合并分片
    await axios.post('http://localhost:5000/merge', {
      fileName: file.name,
      fileHash,
      totalChunks,
    });

    alert('上傳成功!');
    uploading.current = false; // 標(biāo)記上傳完成
  };

  return (
    <div style={{ padding: '20px' }}>
      <p>大文件上傳(支持?jǐn)帱c(diǎn)續(xù)傳)</p>
      <input type="file" onChange={handleFileChange} />
      <button onClick={handleUpload}>提交上傳文件</button>
      <div style={{ marginTop: '20px' }}>
        <progress value={uploadProgress} max="100" />
        <div>上傳進(jìn)度:{uploadProgress.toFixed(2)}%</div>
      </div>
    </div>
  );
}

后端實(shí)現(xiàn)(Node.js)

在后端,您需要安裝以下依賴(lài):multer、fs-extra、expresscors、body-parser。可以使用以下命令:

npm i multer fs-extra express cors body-parser

注意: 這些包應(yīng)用于生產(chǎn)環(huán)境和開(kāi)發(fā)環(huán)境。

以下是Node.js服務(wù)器的實(shí)現(xiàn)代碼:

// 文件:server.js
const express = require("express");
const multer = require("multer");
const fs = require("fs");
const bodyParser = require("body-parser");
const path = require("path");
const cors = require("cors");
const app = express();
const uploadDir = path.join(__dirname, "uploads"); // 上傳目錄

// 確保上傳目錄存在
if (!fs.existsSync(uploadDir)) {
  fs.mkdirSync(uploadDir);
}

app.use(cors()); // 允許跨域請(qǐng)求
app.use(bodyParser.json());
app.use(express.json()); // 解析 JSON 請(qǐng)求體

// 檢查已上傳的分片
app.post("/check", (req, res) => {
  const { fileHash } = req.body;
  console.log("fileHash check",fileHash)

  const fileChunkDir = path.join(uploadDir, fileHash); // 分片存儲(chǔ)目錄
  if (!fs.existsSync(fileChunkDir)) {
    return res.json([]); // 如果目錄不存在,返回空數(shù)組
  }

  // 返回已上傳的分片索引
  const uploadedChunks = fs.readdirSync(fileChunkDir).map((chunk) => {
    return parseInt(chunk.split("-")[1]); // 提取分片索引
  });
  res.json(uploadedChunks);
});


// 設(shè)置 multer 中間件,用于處理文件上傳
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    const fileHash = req.query.fileHash; // 從查詢(xún)參數(shù)獲取 fileHash
    const chunkDir = path.join(uploadDir, fileHash);
    // 確保切片目錄存在
    if (!fs.existsSync(chunkDir)) {
      fs.mkdirSync(chunkDir, { recursive: true });
    }
    cb(null, chunkDir);
  },
  filename: (req, file, cb) => {
    const { chunkIndex } = req.query;
    cb(null, `chunk-${chunkIndex}`);
  },
});

const upload = multer({ storage:storage });

// 上傳文件分片
app.post("/upload", upload.single("chunk"), (req, res) => {
    const { fileHash } = req.body;
    res.status(200).send("分片上傳成功");
});


// 合并分片
app.post("/merge", (req, res) => {
  const { fileName, fileHash, totalChunks } = req.body;
  console.log("fileName",req.body)
  const fileChunkDir = path.join(uploadDir, fileHash);
  const filePath = path.join(uploadDir, fileName);

  // 創(chuàng)建可寫(xiě)流用于最終合并文件
  const writeStream = fs.createWriteStream(filePath);

  for (let i = 0; i < totalChunks; i++) {
    const chunkPath = path.join(fileChunkDir, `chunk-${i}`);
    const data = fs.readFileSync(chunkPath); // 讀取分片
    writeStream.write(data); // 寫(xiě)入最終文件
    // fs.unlinkSync(chunkPath); // 刪除分片文件--留下來(lái),可以看上傳記錄
  }

  writeStream.end(); // 關(guān)閉流
//   fs.rmdirSync(fileChunkDir); // 刪除分片目錄--留下來(lái),可以看上傳記錄
  res.send("文件合并完成");
});

app.listen(5000, () => {
  console.log("服務(wù)器已啟動(dòng):http://localhost:5000");
});

總結(jié)

通過(guò)上述代碼,您可以實(shí)現(xiàn)大文件的分片上傳和斷點(diǎn)續(xù)傳功能。這種方法不僅提高了上傳的可靠性,還能有效應(yīng)對(duì)網(wǎng)絡(luò)的不穩(wěn)定性。

到此這篇關(guān)于React+Node.js實(shí)現(xiàn)大文件傳輸與斷點(diǎn)續(xù)傳的文章就介紹到這了,更多相關(guān)React Node.js大文件傳輸內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 理解react中受控組件和非受控組件及應(yīng)用場(chǎng)景

    理解react中受控組件和非受控組件及應(yīng)用場(chǎng)景

    當(dāng)涉及到React框架時(shí),了解受控組件和非受控組件是非常重要的概念,本文主要介紹了理解react中受控組件和非受控組件及應(yīng)用場(chǎng)景,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • react?表單數(shù)據(jù)形式配置化設(shè)計(jì)

    react?表單數(shù)據(jù)形式配置化設(shè)計(jì)

    這篇文章主要介紹了react表單數(shù)據(jù)形式配置化設(shè)計(jì),文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下
    2022-07-07
  • React Antd Select組件輸入搜索時(shí)調(diào)用接口方式

    React Antd Select組件輸入搜索時(shí)調(diào)用接口方式

    為優(yōu)化Select組件中文輸入時(shí)的接口調(diào)用,使用lodash.debounce實(shí)現(xiàn)防抖,避免每輸入一個(gè)字母即觸發(fā)請(qǐng)求,待用戶(hù)點(diǎn)擊空格完成輸入后,再調(diào)用接口獲取數(shù)據(jù),提升性能與用戶(hù)體驗(yàn)
    2025-08-08
  • React中props使用教程

    React中props使用教程

    props是組件(包括函數(shù)組件和class組件)間的內(nèi)置屬性,用其可以傳遞數(shù)據(jù)給子節(jié)點(diǎn),props用來(lái)傳遞參數(shù)。組件實(shí)例化過(guò)程中,你可以向其中傳遞一個(gè)參數(shù),這個(gè)參數(shù)會(huì)在實(shí)例化過(guò)程中被引用
    2022-09-09
  • 淺談React Hook采用環(huán)形鏈表的原因

    淺談React Hook采用環(huán)形鏈表的原因

    本文主要介紹了淺談React Hook采用環(huán)形鏈表的原因,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2026-06-06
  • 基于React.js實(shí)現(xiàn)兔兔牌九宮格翻牌抽獎(jiǎng)組件

    基于React.js實(shí)現(xiàn)兔兔牌九宮格翻牌抽獎(jiǎng)組件

    這篇文章主要為大家詳細(xì)介紹了如何基于React.js實(shí)現(xiàn)兔兔牌九宮格翻牌抽獎(jiǎng)組件,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2023-01-01
  • ReactDOM 隱藏特性詳解

    ReactDOM 隱藏特性詳解

    這篇文章主要為大家介紹了ReactDOM 隱藏特性詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • 淺談React Event實(shí)現(xiàn)原理

    淺談React Event實(shí)現(xiàn)原理

    這篇文章主要介紹了淺談React Event實(shí)現(xiàn)原理,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-09-09
  • 在React中集成第三方庫(kù)和插件方式

    在React中集成第三方庫(kù)和插件方式

    本文詳細(xì)介紹了如何在React項(xiàng)目中高效集成第三方庫(kù)和插件,包括選擇合適的庫(kù)、封裝為React組件、按需加載、避免直接操作DOM、處理庫(kù)的更新和卸載、樣式處理與主題定制、性能優(yōu)化以及調(diào)試與維護(hù)等方面,通過(guò)遵循這些最佳實(shí)踐,可以確保集成過(guò)程高效且優(yōu)雅
    2025-03-03
  • 利用React高階組件實(shí)現(xiàn)一個(gè)面包屑導(dǎo)航的示例

    利用React高階組件實(shí)現(xiàn)一個(gè)面包屑導(dǎo)航的示例

    這篇文章主要介紹了利用React高階組件實(shí)現(xiàn)一個(gè)面包屑導(dǎo)航的示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08

最新評(píng)論

衡山县| 新泰市| 仙居县| 青冈县| 潜江市| 亳州市| 府谷县| 五峰| 开封市| 河南省| 常州市| 柳江县| 西乌| 孝昌县| 三台县| 苏尼特右旗| 都兰县| 靖宇县| 曲沃县| 黔西县| 灌云县| 阿瓦提县| 前郭尔| 桑植县| 河池市| 恩施市| 囊谦县| 长子县| 济阳县| 元朗区| 渭源县| 新巴尔虎左旗| 沈阳市| 集安市| 宁都县| 中山市| 古丈县| 彰化市| 武川县| 磐安县| 巴彦县|