首页 > web前端 > js教程 > React & Expo - 如何上传和下载文件

React & Expo - 如何上传和下载文件

Patricia Arquette
发布: 2024-12-16 00:30:14
原创
577 人浏览过

介绍

我很难找到关于如何在基于 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中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板