网站LOGO
白雾茫茫丶
页面加载中
1月18日
网站LOGO 白雾茫茫丶
记录学习、生活和有趣的事
菜单
  • 白雾茫茫丶
    记录学习、生活和有趣的事
    用户的头像
    首次访问
    上次留言
    累计留言
    我的等级
    我的角色
    打赏二维码
    打赏博主
    Next.js 实战 (六):如何实现文件本地上传
    点击复制本页信息
    微信扫一扫
    文章二维码
    文章图片 文章标题
    创建时间
  • 一 言
    确认删除此评论么? 确认
  • 本弹窗介绍内容来自,本网站不对其中内容负责。
    • 复制图片
    • 复制图片地址
    • 百度识图
    按住ctrl可打开默认菜单

    Next.js 实战 (六):如何实现文件本地上传

    谢明伟 · 原创 ·
    前端开发Next 实战 · ReactNext
    共 3638 字 · 约 2 分钟 · 156

    前言

    在我们的日常工作中,上传文件、导入 Excel 表格数据这些是不可避免的,那在 Next.js 该如何实现上传文件到本地呢?

    Next.js 的官方文档并没有相应的实例代码,需要开发者自行实现,一般来说有两种思路:

    1. 使用 Node.js 原生上传
    2. 使用第三方插件,如:multer

    本文将以第一种方式实现:使用 Node.js 原生上传

    业务设计

    1. 上传的文件使用哈希值命名,也可自己拼接上原文件名
    2. 文件上传到指定目录,这里我们指令上传的目录为:public/uploads,因为上传到这个目录,我们就能直接通过 /uploads/xxx.jpg 访问文件
    3. 上传目录的文件夹将以 YYYYMM 年月的格式分类,可以自定义

    具体步骤

    新建 app/api/upload/route.ts 文件,写入代码:

    ts 代码:
    import crypto from 'crypto';
    import dayjs from 'dayjs';
    import { existsSync } from 'fs';
    import fs from 'fs/promises';
    import { NextRequest, NextResponse } from 'next/server';
    import path from 'path';
    
    import { RESPONSE_MSG } from '@/enums';
    import { responseMessage } from '@/lib/utils';
    
    export async function POST(req: NextRequest) {
      try {
        // 获取二进制文件数据
        const formData = await req.formData();
    
        const f = formData.get('file');
    
        if (!f) {
          return NextResponse.json({}, { status: 400 });
        }
    
        const file = f as File;
    
        const yearMonth = dayjs().format('YYYYMM');
    
        // 获取当前年月并创建对应的文件夹
        const uploadDir = path.join(process.cwd(), 'public/uploads', yearMonth);
    
        // 如果文件夹不存在,则创建
        if (!existsSync(uploadDir)) {
          await fs.mkdir(uploadDir, { recursive: true });
        }
    
        // 将文件保存到服务器的文件系统中
        const fileArrayBuffer = await file.arrayBuffer();
    
        // 生成哈希值作为文件名
        const hash = crypto.randomBytes(16).toString('hex');
    
        // 生成文件名
        const fileName = `${hash}.${file.name.split('.')[1]}`;
    
        // 将文件上传到 uploads 文件夹
        await fs.writeFile(path.join(uploadDir, fileName), Buffer.from(fileArrayBuffer));
    
        return NextResponse.json(
          responseMessage({
            fileName,
            size: file.size,
            url: `/uploads/${yearMonth}/${fileName}`,
          }),
        );
      } catch (error) {
        return NextResponse.json(responseMessage(error, RESPONSE_MSG.ERROR, -1));
      }
    }

    代码都有注释,我感觉还是比较好容易理解的

    前端使用

    前端可以通过 FormData 格式提交数据:

    html 代码:
    // 上传头像
      const { loading: uploadLoading, run: runUploadAvatar } = useRequest(uploadFile, {
        manual: true,
        onSuccess: ({ code, data }) => {
          if (isSuccess(code)) {
            setAvatar(data.url);
          }
        },
      });
    
      // 图片上传回调
      const handleFileChange: ChangeEventHandler<HTMLInputElement> = (event) => {
        const file = event.target.files?.[0];
        if (file) {
          // 创建一个 FormData 对象
          const formData = new FormData();
          formData.append('file', file);
          runUploadAvatar(formData);
        }
      };
    
    <Input
      name="avatar"
      type="file"
      accept="image/*"
      className="w-20"
      onChange={handleFileChange}
      size="sm"
      />

    效果演示

    我们通过 postman 模拟上传:

    上传后的文件夹结构:

    总结

    这里只实现了单个文件上传,批量上传或者文件数组的需要自行实现

    现在很多公司文件存储业务都已经使用第三方平台,比如:

    1. 阿里云 OSS
    2. 腾讯云 COS
    3. 七牛云 KODO
    4. 又拍云 USS

    很少用上传到服务器本地的,业务量大的话会对服务器造成压力,一般这种适合个人站点、博客使用,这里我们当做学习就行。

    Githubnext-admin
    线上预览地址Next Admin

    声明:本文由 谢明伟(博主)原创,依据 CC-BY-NC-SA 4.0 许可协议 授权,转载请注明出处。

    还没有人喜爱这篇文章呢

    我要发表评论 我要发表评论
    博客logo 白雾茫茫丶 记录学习、生活和有趣的事 51统计 百度统计
    MOEICP 萌ICP备20236860号 ICP 粤ICP备2023007649号 ICP 粤公网安备44030402006402号

    💻️ 谢明伟 昨天 17:26 在线

    🕛

    本站已运行 3 年 17 天 16 小时 21 分

    🌳

    自豪地使用 Typecho 建站,并搭配 MyLife 主题
    白雾茫茫丶. © 2022 ~ 2025.
    网站logo

    白雾茫茫丶 记录学习、生活和有趣的事