关于 uploadthing-nextjs
面向 Next.js 和 TypeScript 应用的 UploadThing 集成技能,用于规划类型安全的文件上传流程。内容涵盖路由规则、中间件授权、上传后处理及服务端 API。
主要功能
- 01按路由配置文件类型和限制
- 02上传前执行身份验证与授权
- 03处理上传完成后的逻辑
- 04服务端上传、删除和列出文件
- 05为私有文件生成签名 URL
适用场景
- 01实现带权限校验的头像上传
- 02为附件配置不同上传规则
- 03在服务端任务中上传或迁移文件
- 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
});
数据库集成模式
上传完成后,应用应当:
- 存储 UploadThing 文件标识符
- 存储公开或签名文件 URL
- 存储所有权元数据
- 将文件关联到领域实体(帖子、个人资料、资产等)
.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 };
})
上传策略
客户端上传(推荐)
流程:
- 客户端请求上传授权
- 服务端返回预签名上传 URL
- 客户端直接上传到存储
- 上传完成处理器运行服务端逻辑
服务端上传(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