当前位置: 首页 > article >正文

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

前言

在我们的日常工作中,上传文件、导入 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 文件,写入代码:

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 格式提交数据:

// 上传头像
  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

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

Github:next-admin


http://www.kler.cn/a/465344.html

相关文章:

  • Spring Boot - 日志功能深度解析与实践指南
  • FastAPI 路由与请求处理机制
  • Scala_【4】流程控制
  • Swift Protocols(协议)、Extensions(扩展)、Error Handling(错误处理)、Generics(泛型)
  • vue——滑块验证
  • 【Pytorch报错】AttributeError: cannot assign module before Module.__init__() call
  • 目录中只有一个子目录时把子目录移动到父目录
  • OpenCV的人脸检测模型FaceDetectorYN
  • 25考研王道数据结构课后习题笔记
  • 2025三掌柜赠书活动第一期:动手学深度学习(PyTorch版)
  • 什么是实体完整性约束?
  • CSS系列(43)-- Anchor Positioning详解
  • Python图形界面(GUI)Tkinter笔记(二十二):Listbox列表项目功能控件
  • 在C#中获取程序的命令行参数
  • Spring MVC 的@GetMapping和@PostMapping和@PutMapping
  • Maven项目集成SQL Server的完整教程:从驱动配置到封装优化
  • Unity小白工作心得(无限记录)
  • uniapp中使用ruoyiPlus中的加密使用(crypto-js)
  • es 3期 第19节-运用异步机制执行重度查询
  • 面向对象三大特征之一——继承super
  • Sentinel的源码学习记录
  • 服务器主机网络测试命令
  • 2024 年终总结
  • 数据篇---用python创建想要的xml
  • [python SQLAlchemy数据库操作入门]-21.SQLAlchemy Session生命周期管理:保持数据持久化
  • 网络安全 | 防护层次:从物理到应用的多重保障