mcpField
U
uploadthing-nextjs

uploadthing-nextjs

github.com/flohhhhh开发249 次安装32 周前更新
代码仓库

关于 uploadthing-nextjs

面向 Next.js 和 TypeScript 应用的 UploadThing 集成技能,用于规划类型安全的文件上传流程。内容涵盖路由规则、中间件授权、上传后处理及服务端 API。

主要功能

  1. 01按路由配置文件类型和限制
  2. 02上传前执行身份验证与授权
  3. 03处理上传完成后的逻辑
  4. 04服务端上传、删除和列出文件
  5. 05为私有文件生成签名 URL

适用场景

  1. 01实现带权限校验的头像上传
  2. 02为附件配置不同上传规则
  3. 03在服务端任务中上传或迁移文件
  4. 04为私有文件创建限时访问链接

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/flohhhhh/skills --skill uploadthing-nextjs

安装后在 Claude Code 中输入/uploadthing-nextjs确认已加载。

详细介绍

UploadThing 集成(Next.js)

UploadThing 为现代 TypeScript Web 应用提供类型安全、直接上传到存储的文件上传系统。


适用场景

当应用需要以下功能时,使用 UploadThing:

  • 安全的用户文件上传
  • 类型安全的上传工作流
  • 按功能配置的上传权限和验证
  • 适用于 React/Next.js 的上传组件
  • 无需构建自定义上传管道的存储抽象

不适用场景

遇到以下情况时,避免使用或重新考虑:

  • 存储前需要深度、多阶段的处理管道
  • 需要在服务端完全控制二进制数据流
  • 架构要求将存储提供商 API 作为主要数据源,而非数据库

核心概念

File Router

定义应用的所有上传路由。

每个路由定义:

  • 允许的文件类型
  • 文件限制和大小规则
  • 身份验证检查
  • 元数据处理
  • 上传后处理

File Route

表示一种单独的上传用例。

示例:

  • 用户头像上传
  • 车辆列表图片
  • 消息附件
  • 文档上传

Middleware

在上传开始前运行。

用于:

  • 身份验证
  • 授权
  • 元数据标记
  • 拒绝无效上传

上传完成处理器

在文件成功上传后运行。

用于:

  • 将元数据保存到数据库
  • 将文件关联到领域实体
  • 触发异步处理
  • 发送通知

UTApi

UploadThing 服务端 SDK。

用于:

  • 以编程方式上传文件
  • 删除文件
  • 列出文件(仅限管理/调试)
  • 为私有文件访问生成签名 URL

安装

npm install uploadthing @uploadthing/react

环境变量

# .env
UPLOADTHING_SECRET=sk_live_...
UPLOADTHING_APP_ID=your_app_id

建议的文件结构

app/
  api/
    uploadthing/
      core.ts        # File router definition
      route.ts       # API route handlers
src/
  utils/
    uploadthing.ts   # Typed components
  components/
    upload-button.tsx
.env                 # UploadThing credentials

File Router

位置: app/api/uploadthing/core.ts

import { createUploadthing, type FileRouter } from "uploadthing/next";
import { auth } from "@/lib/auth";

const f = createUploadthing();

export const uploadRouter = {
  imageUploader: f({ image: { maxFileSize: "4MB", maxFileCount: 1 } })
    .middleware(async ({ req }) => {
      const user = await auth();
      if (!user) throw new Error("Unauthorized");
      return { userId: user.id };
    })
    .onUploadComplete(async ({ metadata, file }) => {
      console.log("Upload complete for userId:", metadata.userId);
      console.log("File URL:", file.url);
      // Save to database here
      return { uploadedBy: metadata.userId };
    }),
} satisfies FileRouter;

export type OurFileRouter = typeof uploadRouter;

路由处理器

位置: app/api/uploadthing/route.ts

import { createRouteHandler } from "uploadthing/next";
import { uploadRouter } from "./core";

export const { GET, POST } = createRouteHandler({
  router: uploadRouter,
});

类型化上传组件

位置: src/utils/uploadthing.ts

import {
  generateUploadButton,
  generateUploadDropzone,
} from "@uploadthing/react";
import type { OurFileRouter } from "@/app/api/uploadthing/core";

export const UploadButton = generateUploadButton<OurFileRouter>();
export const UploadDropzone = generateUploadDropzone<OurFileRouter>();

使用上传组件

"use client";

import { UploadButton } from "@/utils/uploadthing";

export function MyUploadButton() {
  return (
    <UploadButton
      endpoint="imageUploader"
      onClientUploadComplete={(res) => {
        console.log("Files: ", res);
        alert("Upload Completed");
      }}
      onUploadError={(error: Error) => {
        alert(`ERROR! ${error.message}`);
      }}
    />
  );
}

Tailwind 集成(可选)

import { withUt } from "uploadthing/tw";

export default withUt({
  // your tailwind config
  content: ["./src/**/*.{ts,tsx}"],
  theme: { extend: {} },
  plugins: [],
});

可选 — SSR 上传配置优化

// next.config.js
import { withUT } from "uploadthing/nextjs";

export default withUT({
  // your Next.js config
});

数据库集成模式

上传完成后,应用应当:

  1. 存储 UploadThing 文件标识符
  2. 存储公开或签名文件 URL
  3. 存储所有权元数据
  4. 将文件关联到领域实体(帖子、个人资料、资产等)
.onUploadComplete(async ({ metadata, file }) => {
  await db.insert(uploads).values({
    userId: metadata.userId,
    fileKey: file.key,
    fileUrl: file.url,
    fileName: file.name,
    fileSize: file.size,
  });
  
  return { success: true };
})

上传策略

客户端上传(推荐)

流程:

  1. 客户端请求上传授权
  2. 服务端返回预签名上传 URL
  3. 客户端直接上传到存储
  4. 上传完成处理器运行服务端逻辑

服务端上传(UTApi)

适用于:

  • 从服务端任务上传文件
  • 迁移文件
  • 处理管理工具
  • 通过服务端操作接收文件
import { UTApi } from "uploadthing/server";

const utapi = new UTApi();

export async function uploadFromServer(file: File) {
  const response = await utapi.uploadFiles(file);
  return response.data;
}

私有文件访问模式

应通过签名 URL 访问私有文件。

import { UTApi } from "uploadthing/server";

const utapi = new UTApi();

export async function getPrivateFileUrl(fileKey: string) {
  const url = await utapi.getSignedURL(fileKey, { expiresIn: "1h" });
  return url;
}

安全最佳实践

  • 始终在上传中间件中进行身份验证
  • 在数据库中存储所有权和文件元数据
  • 创建多个专用上传路由
  • 避免使用全局的“上传所有内容”路由
  • 在上传完成时验证领域关联关系

运维最佳实践

  • 记录文件键和存储 URL
  • 确保数据库写入具备幂等性
  • 优先在本地存储元数据,而不是查询存储提供商
  • 限制每个路由的文件大小和数量
  • 将公开和私有上传路由分开

常见错误

  • 使用未类型化的 UploadThing 组件
  • 忘记客户端组件指令
  • 跳过数据库元数据存储
  • 允许权限过于宽泛的上传路由
  • 将存储提供商 API 作为主要数据源

总结

UploadThing 管理文件上传和存储。

Next.js 提供路由和集成接口。

将上传规则放在文件路由中。将授权逻辑放在中间件中。将文件元数据存储在数据库中。


References

评论

支持 Markdown