首頁 >web前端 >js教程 >React & Expo - 如何上傳下載文件

React & Expo - 如何上傳下載文件

Patricia Arquette
Patricia Arquette原創
2024-12-16 00:30:14578瀏覽

介紹

我很難找到關於如何在基於 Expo 的行動應用程式中上傳和下載檔案的清晰範例。為了幫助面臨同樣挑戰的其他人或任何只是好奇的人,我寫了這篇文章。

在這個過程中,我們將探索有助於理解的關鍵概念:

  • 緩衝區
  • 意圖過濾器
  • MIME 類型
  • 應用程式/八位元位元組流
  • 多部分/表單資料
  • 還有更多...

我們將要涵蓋的內容:

  • 使用 Fastify 伺服器傳送和接收檔案。
  • 在 React Web 應用程式上傳、下載和顯示檔案。
  • 在 React Native (Expo) 行動應用程式上傳、下載和顯示檔案。

所有程式碼Postman集合都可以在我的GitHub上找到。

伺服器

React & Expo - How to Upload & Download Files

伺服器在Fastify(Express.js 的現代化版本)上運作。要啟動應用程序,請執行以下操作:

  1. 使用終端導航到 /server
  2. 使用 npm install 安裝依賴項
  3. 使用 npm run dev 運行伺服器

在 app.js 中,我們有三個關鍵端點:

- 下載端點(/download)

fastify.get("/download", async function handler(_, reply) {
  const fd = await open(FILE_TO_DOWNLOAD);
  const stream = fd.createReadStream();

  const mimeType = mime.lookup(FILE_TO_DOWNLOAD);

  console.log(`Downloading -> ${FILE_TO_DOWNLOAD}`);

  return reply
    .type(mimeType)
    .header(
      "Content-Disposition",
      `attachment; filename=${path.basename(FILE_TO_DOWNLOAD)}`
    )
    .send(stream);
});

此端點使用 createReadStream() 將 example.webp 傳送為流。包含 MIME 類型,以便用戶端知道如何處理該檔案。例如.webp,這將是image/webp。

?注意:MIME 類型定義了正在傳送的文件的格式。這有助於客戶端正確顯示它。
查看更多 MIME 類型。

Content-Disposition 標頭定義如何將內容呈現給客戶端。包括附件;文件名=;提示瀏覽器下載文件而不是內聯顯示它。若要直接顯示它,請使用內聯而不是附件。
了解更多有關內容處置的資訊

React & Expo - How to Upload & Download Files

- 使用表單資料上傳多個檔案(/upload-multiples)

fastify.post("/upload-multiples", async function handler(request) {
  const parts = request.files();
  const uploadResults = [];

  for await (const file of parts) {
    const fileBuffer = await file.toBuffer();
    const filename = file.filename;
    const filePath = path.join(DIR_TO_UPLOAD, filename);

    await writeFile(filePath, fileBuffer);
    uploadResults.push({ filename, uploaded: true });
    console.log(`Uploaded -> ${filePath}`);
  }

  return { uploadedFiles: uploadResults };
});

此端點接受多部分/表單資料請求。它:

  1. 從請求中檢索文件。
  2. 將每個檔案轉換為緩衝區(二進位資料的 JavaScript 表示)。
  3. 將檔案儲存到 /upload 目錄。

例如,請求可能如下所示:

React & Expo - How to Upload & Download Files

- 使用八位元組流上傳檔案 (/upload-octet-stream)

fastify.get("/download", async function handler(_, reply) {
  const fd = await open(FILE_TO_DOWNLOAD);
  const stream = fd.createReadStream();

  const mimeType = mime.lookup(FILE_TO_DOWNLOAD);

  console.log(`Downloading -> ${FILE_TO_DOWNLOAD}`);

  return reply
    .type(mimeType)
    .header(
      "Content-Disposition",
      `attachment; filename=${path.basename(FILE_TO_DOWNLOAD)}`
    )
    .send(stream);
});

此端點期望請求正文中有一個二進位檔案(應用程式/八位元組流)。與multipart/form-data不同的是,該檔案已經是二進位資料了,所以我們可以直接將其寫入磁碟。

請求在 Postman 中看起來像這樣:

React & Expo - How to Upload & Download Files

React & Expo - How to Upload & Download Files

網路(反應)



React & Expo - How to Upload & Download Files

運行應用程式:

  1. 使用終端導航到 /web
  2. 使用 npm install 安裝依賴項
  3. 使用 npm run dev 啟動應用程式

Web 應用程式的所有功能都包含在 App.tsx 中:

React & Expo - How to Upload & Download Files

這個 React 應用程式提供三個關鍵功能:

- 下載/顯示文件

fastify.post("/upload-multiples", async function handler(request) {
  const parts = request.files();
  const uploadResults = [];

  for await (const file of parts) {
    const fileBuffer = await file.toBuffer();
    const filename = file.filename;
    const filePath = path.join(DIR_TO_UPLOAD, filename);

    await writeFile(filePath, fileBuffer);
    uploadResults.push({ filename, uploaded: true });
    console.log(`Uploaded -> ${filePath}`);
  }

  return { uploadedFiles: uploadResults };
});

當使用者點擊「下載」按鈕時,應用程式:

  1. 呼叫 /download 端點。
  2. 以二進位 blob 形式接收檔案。
  3. 從 blob 建立一個 objectURL,充當瀏覽器可以存取的臨時 URL。

行為取決於伺服器傳回的 Content-Disposition 標頭:

  • 如果 Content-Disposition 包含內聯,則檔案將顯示在新選項卡中。
  • 如果包含附件,則會自動下載該檔案。

為了觸發下載,應用程式會建立一個臨時的 ; href 設定為 objectURL 的元素並以程式設計方式點擊它,模擬使用者下載操作。

- 使用表單資料上傳文件

fastify.post("/upload-octet-stream", async function handler(request) {
  const filename = request.headers["x-file-name"] ?? "unknown.text";

  const data = request.body;
  const filePath = path.join(DIR_TO_UPLOAD, filename);

  await writeFile(filePath, data);

  return { uploaded: true };
});

點選「上傳檔案」按鈕時:

  1. uploadFile 函數運行,建立一個隱藏的 元素並模擬使用者點擊。
  2. 一旦使用者選擇一個或多個文件,這些文件就會附加到 FormData 物件。
  3. 請求被傳送到 /upload-multiples 端點,該端點透過 multipart/form-data 接受檔案。

這使得伺服器能夠正確處理和保存上傳的檔案。

- 使用八位元組流上傳文件

  const downloadFile = async () => {
    const response = await fetch(DOWNLOAD_API);

    if (!response.ok) throw new Error("Failed to download file");

    const blob = await response.blob();

    const contentDisposition = response.headers.get("Content-Disposition");

    const isInline = contentDisposition?.split(";")[0] === "inline";
    const filename = contentDisposition?.split("filename=")[1];

    const url = window.URL.createObjectURL(blob);

    if (isInline) {
      window.open(url, "_blank");
    } else {
      const a = document.createElement("a");
      a.href = url;
      a.download = filename || "file.txt";
      a.click();
    }

    window.URL.revokeObjectURL(url);
  };

這種方法比使用 multipart/form-data 更簡單 - 只需將檔案作為二進位資料直接在請求正文中發送,並將檔案名稱包含在請求標頭中。

移動(世博會)



React & Expo - How to Upload & Download Files

您可以使用以下命令啟動應用程式:

  1. 導航到終端中的移動目錄。
  2. 安裝依賴項:npm install
  3. 使用 npm run android 或 npm run ios 來執行項目

主要邏輯位於 App.tsx 中,它呈現以下內容:

fastify.get("/download", async function handler(_, reply) {
  const fd = await open(FILE_TO_DOWNLOAD);
  const stream = fd.createReadStream();

  const mimeType = mime.lookup(FILE_TO_DOWNLOAD);

  console.log(`Downloading -> ${FILE_TO_DOWNLOAD}`);

  return reply
    .type(mimeType)
    .header(
      "Content-Disposition",
      `attachment; filename=${path.basename(FILE_TO_DOWNLOAD)}`
    )
    .send(stream);
});

要在新視圖中顯示檔案(就像瀏覽器在新分頁中開啟檔案一樣),我們必須將回應作為 blob 讀取,然後使用 FileReader 將其轉換為 base64。

我們將檔案寫入快取目錄(只有應用程式可以存取的私有目錄),然後使用 IntentLauncher 或共用(如果使用者使用 iOS)顯示它。

- 下載文件

fastify.post("/upload-multiples", async function handler(request) {
  const parts = request.files();
  const uploadResults = [];

  for await (const file of parts) {
    const fileBuffer = await file.toBuffer();
    const filename = file.filename;
    const filePath = path.join(DIR_TO_UPLOAD, filename);

    await writeFile(filePath, fileBuffer);
    uploadResults.push({ filename, uploaded: true });
    console.log(`Uploaded -> ${filePath}`);
  }

  return { uploadedFiles: uploadResults };
});

這與 Web 進程類似,但我們必須使用 FileReader 將 blob 讀取為 base64,然後請求權限將檔案下載到使用者想要儲存檔案的位置。

- 使用表單資料上傳文件

fastify.post("/upload-octet-stream", async function handler(request) {
  const filename = request.headers["x-file-name"] ?? "unknown.text";

  const data = request.body;
  const filePath = path.join(DIR_TO_UPLOAD, filename);

  await writeFile(filePath, data);

  return { uploaded: true };
});

使用 DocumentPicker 使用戶能夠選擇文件,然後使用 FormData 將所選文件附加到請求中。過程非常簡單。

- 將檔案上傳為八位元組流

  const downloadFile = async () => {
    const response = await fetch(DOWNLOAD_API);

    if (!response.ok) throw new Error("Failed to download file");

    const blob = await response.blob();

    const contentDisposition = response.headers.get("Content-Disposition");

    const isInline = contentDisposition?.split(";")[0] === "inline";
    const filename = contentDisposition?.split("filename=")[1];

    const url = window.URL.createObjectURL(blob);

    if (isInline) {
      window.open(url, "_blank");
    } else {
      const a = document.createElement("a");
      a.href = url;
      a.download = filename || "file.txt";
      a.click();
    }

    window.URL.revokeObjectURL(url);
  };

作為 Application/octet-stream 上傳比使用 FormData 更簡單:使用文件詳細資訊和內容類型設定標頭,然後將文件新增至請求正文,就是這樣!

結論

如何在平台之間查看、下載和上傳檔案可能有點令人困惑,在這篇文章中我們看到了最常見的。

希望對您有幫助?

讓我在@twitter上

以上是React & Expo - 如何上傳下載文件的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn