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

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

Dec 16, 2024 am 12:30 AM

介绍

我很难找到关于如何在基于 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

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

热门话题

Java教程
1664
14
CakePHP 教程
1423
52
Laravel 教程
1317
25
PHP教程
1268
29
C# 教程
1242
24
神秘的JavaScript:它的作用以及为什么重要 神秘的JavaScript:它的作用以及为什么重要 Apr 09, 2025 am 12:07 AM

JavaScript是现代Web开发的基石,它的主要功能包括事件驱动编程、动态内容生成和异步编程。1)事件驱动编程允许网页根据用户操作动态变化。2)动态内容生成使得页面内容可以根据条件调整。3)异步编程确保用户界面不被阻塞。JavaScript广泛应用于网页交互、单页面应用和服务器端开发,极大地提升了用户体验和跨平台开发的灵活性。

JavaScript的演变:当前的趋势和未来前景 JavaScript的演变:当前的趋势和未来前景 Apr 10, 2025 am 09:33 AM

JavaScript的最新趋势包括TypeScript的崛起、现代框架和库的流行以及WebAssembly的应用。未来前景涵盖更强大的类型系统、服务器端JavaScript的发展、人工智能和机器学习的扩展以及物联网和边缘计算的潜力。

JavaScript引擎:比较实施 JavaScript引擎:比较实施 Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和执行JavaScript代码时,效果会有所不同,因为每个引擎的实现原理和优化策略各有差异。1.词法分析:将源码转换为词法单元。2.语法分析:生成抽象语法树。3.优化和编译:通过JIT编译器生成机器码。4.执行:运行机器码。V8引擎通过即时编译和隐藏类优化,SpiderMonkey使用类型推断系统,导致在相同代码上的性能表现不同。

Python vs. JavaScript:学习曲线和易用性 Python vs. JavaScript:学习曲线和易用性 Apr 16, 2025 am 12:12 AM

Python更适合初学者,学习曲线平缓,语法简洁;JavaScript适合前端开发,学习曲线较陡,语法灵活。1.Python语法直观,适用于数据科学和后端开发。2.JavaScript灵活,广泛用于前端和服务器端编程。

JavaScript:探索网络语言的多功能性 JavaScript:探索网络语言的多功能性 Apr 11, 2025 am 12:01 AM

JavaScript是现代Web开发的核心语言,因其多样性和灵活性而广泛应用。1)前端开发:通过DOM操作和现代框架(如React、Vue.js、Angular)构建动态网页和单页面应用。2)服务器端开发:Node.js利用非阻塞I/O模型处理高并发和实时应用。3)移动和桌面应用开发:通过ReactNative和Electron实现跨平台开发,提高开发效率。

如何使用Next.js(前端集成)构建多租户SaaS应用程序 如何使用Next.js(前端集成)构建多租户SaaS应用程序 Apr 11, 2025 am 08:22 AM

本文展示了与许可证确保的后端的前端集成,并使用Next.js构建功能性Edtech SaaS应用程序。 前端获取用户权限以控制UI的可见性并确保API要求遵守角色库

使用Next.js(后端集成)构建多租户SaaS应用程序 使用Next.js(后端集成)构建多租户SaaS应用程序 Apr 11, 2025 am 08:23 AM

我使用您的日常技术工具构建了功能性的多租户SaaS应用程序(一个Edtech应用程序),您可以做同样的事情。 首先,什么是多租户SaaS应用程序? 多租户SaaS应用程序可让您从唱歌中为多个客户提供服务

从C/C到JavaScript:所有工作方式 从C/C到JavaScript:所有工作方式 Apr 14, 2025 am 12:05 AM

从C/C 转向JavaScript需要适应动态类型、垃圾回收和异步编程等特点。1)C/C 是静态类型语言,需手动管理内存,而JavaScript是动态类型,垃圾回收自动处理。2)C/C 需编译成机器码,JavaScript则为解释型语言。3)JavaScript引入闭包、原型链和Promise等概念,增强了灵活性和异步编程能力。

See all articles