Next.js 如何上传大型静态资源?

阅读时长 8 分钟读完

Next.js 是基于 React 的服务端渲染框架。它提供了很多便利的功能,比如代码分割、预测性路由、数据预取等,使得我们能够快速构建高性能的 Web 应用。然而,在面对一些静态资源(如图片、音视频等)的上传和管理时,Next.js 并没有提供很好的解决方案,本文将介绍一种可行的方法。

问题

在 Next.js 中,我们通常使用 next/image 组件来引入图片。它可以自动根据屏幕的分辨率和当前网速,生成适合的图片大小和质量,从而提升用户体验。然而,当你需要上传一些大型静态资源时,如何让它们能够被正确地加载呢?我们考虑将它们存放在一个 CDN 中,让它充分发挥出 “分布式静态资源服务” 的优势。但一方面,Next.js 并没有直接的 API 支持 CDN 的上传,另一方面,如果采用传统的上传方式,很可能会遇到以下问题:

  • 上传的过程耗时较长,会阻塞渲染线程,导致页面卡顿。
  • 如果上传的资源过大,可能会导致某些用户的上传失败或上传速度较慢。而用户是无法得知哪些资源上传成功、失败或正在上传的。
  • CDN 的上传接口可能会受到一些限制,如单个文件大小、同时上传个数、上传间隔等,我们需要考虑这些限制如何优雅地处理。

解决方案

我们可以采用一种类似于“分片上传”的方式,将大型静态资源切割成若干个小块,每个小块一个个地上传到 CDN 上,上传成功后将其地址保存起来。而在下载时,只需将多个小块链接拼接起来即可,如下图所示:

这种方式能够避免同时上传过多文件所导致的资源浪费;对于上传失败的小块,我们可以对其进行重传,而不需要将整个大块重新上传。除此之外,在上传过程中,我们还可以通过 WebSocket、Server-Sent Events 等技术实现实时进度更新等功能。

接下来,我们将会基于 Next.js 和 Uppy 这个优秀的文件上传库,实现一个 “分片上传” 的示例。项目地址:ice-raven/nextjs-upload-demo

实现步骤

集成 Uppy

首先,我们需要引入 Uppy 并配置它。我们可以通过 npmyarn 安装:

我们需要创建一个 Uppy 对象来管理上传功能;并使用 Uppy 的插件 XHRUpload 对文件进行上传。下面是一个简单的配置:

-- -------------------- ---- -------
------ ---- ---- -------------
------ --------- ---- -------------------

----- ---- - ------
  ------------ -----
---

------------------- -
  --------- -----------------------------
---

分割文件

我们需要将文件分割成固定大小的小块。这里我们使用 File.slice() 方法进行分割。

-- -------------------- ---- -------
-------- --------------- ---- - ----- -
  --- ----- - --
  --- --- - -----
  ----- ------ - ---
  ----- ------ - ---------- -
    ----------------------------- ------
    ----- - ----
    --- - ----- - -----
  -
  ------ -------
-

上传小块

接下来,我们需要使用 Uppy 的 API 对每个小块进行上传,并将上传成功后返回的文件地址进行保存。

-- -------------------- ---- -------
-------- ------------------ -
  ----- ------ - ----------------
  ----- -------- - ------------------ ------ -- -
    ------ -------------------------------- -- -
      ------ - ------ --------- ----------- --
    ---
  ---
  ------ ----------------------
-

这里的 response 是上传成功后,CDN 返回的 JSON 数据格式。我们需要从中提取出文件的地址并返回,如下:

拼接文件

最后,我们需要将文件中的小块地址拼接成一个完整的 URL。

完整示例代码

下面是一个完整的 Next.js 页面,它可以上传文件并显示出上传后的图片。

-- -------------------- ---- -------
------ - -------- - ---- --------
------ ---- ---- -------------
------ --------- ---- -------------------

----- ---- - ------
  ------------ -----
---

------------------- -
  --------- -----------------------------
---

----- -------- - --------------------------

-------- --------------- ---- - ----- -
  --- ----- - --
  --- --- - -----
  ----- ------ - ---
  ----- ------ - ---------- -
    ----------------------------- ------
    ----- - ----
    --- - ----- - -----
  -
  ------ -------
-

-------- ------------------------- -
  ----- -------- - ------------------------------
  ----- -- - ------------------------------
  ------ --------------------------------
-

-------- ------------------ -
  ----- ------ - ----------------
  ----- -------- - ------------------ ------ -- -
    ------ -------------------------------- -- -
      ------ - ------ --------- ----------- --
    ---
  ---
  ------ ------------------------------------ -- -
    ---------------- -- -- ------- - ---------
    ------ --------------- -- -----------------------------
  ---
-

-------- ------------------ -
  ----- ---- - --- -------------
  ------ --------------------------
-

------ ------- -------- ---------- -
  ----- --------- ----------- - -------------

  ----- ---------------- - ----- --- -- -
    ----- ---- - ------------------
    -- ------- -------
    ----- ---- - ----- -------------------
    -----------------------------
  --

  ------ -
    -----
      ------ ----------- --------------------------- --
      -------- -- ---- ------------- ------------ ---
    ------
  --
-

总结

通过上述示例,我们可以看出 “分片上传” 的方式确实能够解决上传大型静态资源的问题,并且对于后续的管理和维护也有很大的帮助。当然,在实际项目中,还需要考虑诸如安全、CDN 版本控制、错误处理等问题。希望本文能够为大家提供一些思路和参考,使得我们在 Next.js 中上传大型静态资源更加得心应手。

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/6461860a968c7c53b02e5af8

纠错
反馈