这是Pina塔挑战的提交
我创建的Uploadnow 是一个允许用户轻松上传和管理文件(图片、视频、音频等)的网络应用。它使用 Pinata 来存储和检索,从而为资产管理工作提供了一个安全且一致的环境。此项目是 Pinata 挑战赛的提交作品。我的灵感来自 Uploadthing。
要初始化一个新的 ShadCN Next.js 项目,可以运行下面的命令:
运行以下命令来初始化项目: npx shadcn@latest init 或者 pnpm dlx shadcn@latest init
全屏,退出
创建一个名为 .env.local
的文件,并将以下内容粘贴进去:,
PINATA_API_KEY="" PINATA_API_SECRET="" PINATA_GATEWAY="*.mypinata.cloud" PINATA_JWT="" # è®°é¢ANCER `npx convex dev` 解颮 CONVEX_DEPLOYMENT="" NEXT_PUBLIC_CONVEX_URL="" # 记颮讵権屮 FINGER_PRINT_API_KEY=""
全屏,退出全屏
upload
、cancel
、retry
和remove file
等操作。该项目需要Pinata的凭证,然后请前往[仪表板]查看详情。
给密钥取个名字,选好权限后,点击一下生成密钥。
已部署的应用版本可以在Uploadnow查看。
看看上传队列
上传进度如下,
我的程序代码这是由 Next.js 提供的路由处理器。它是一个 POST 请求处理器(handler),接收文件和其他必要的信息。通过调用 await pinata.upload.file(file)
方法,并将文件对象作为第一个参数传递,将文件传递给 Pinata
的 JavaScript SDK。
export const POST = async (req: Request) => { try { const form = await req.formData(); const file = form.get("file") as File; const sidebarId = form.get("sideBarId") as Sidebar; const fingerPrintId = form.get("visitorId") as string; if (!file || !sidebarId || !fingerPrintId) { return Response.json( { message: "请求无效,请提供所有参数。" }, { status: 403 } ); } const upload = await Pinata.upload.file(file); const convexDb = await fetchMutation(api.files.createFile, { sidebarId, fingerPrintId, pinataId: upload.id, filename: upload.name, pinataCid: upload.cid, mimeType: upload.mime_type, pinataCreatedAt: upload.created_at, }); if (!convexDb) { return Response.json( { message: "无法上传文件,请重试上传。", uploaded: false }, { status: 500 } ); } return Response.json({ message: convexDb.message, uploaded: true }); } catch (err: any) { console.error(err); return Response.json( { message: "服务器内部错误,请稍后再试。" }, { status: 500 } ); } };
切换到全屏 退出全屏
因为这个项目用的是Convex,所以我们要设置数据库结构。由于我们使用了Fingerprint.js,所以不需要单独的用户表。
import { defineSchema, defineTable, GenericSchema } from "convex/server"; import { v } from "convex/values"; // 定义文件模式 export default defineSchema({ files: defineTable({ // 文件指纹ID fingerPrintId: v.string(), // Pinata ID pinataId: v.string(), // Pinata Cid pinataCid: v.string(), // 文件名 filename: v.string(), // MIME类型 mimeType: v.string(), // Pinata创建时间 pinataCreatedAt: v.string(), // 侧边栏ID sidebarId: v.union( v.literal("all"), v.literal("audios"), v.literal("videos"), v.literal("images"), v.literal("documents"), v.literal("archives") ), }), });
全屏,退出全屏
Uploadnow这个项目的完整源代码可以在GitHub访问。
了解更多我最初的计划是将Pinata中的群组功能整合进来,但由于群组列表的方法不起作用,我不得不重新考虑一下这个功能是否可行。
const groups = await pinata.groups.list();
这行代码用于从pinata的groups列表中获取分组信息。
切换到全屏 / 退出全屏
当该方法被调用时,它只是返回一个空数组。即使更改了秘密凭证也无法使其工作。最终REST API才开始能用上了,而那时我已经转向了其他功能。在REST API和SDK之间切换体验并不好。
发送失败:无法从客户端发送资产
Pinata 的 API 很直观,但我找不到从客户端直接将资产发送到 Pinata 的方法。此功能可以节省服务器资源,因为它可以直接从客户端上传到 Pinata,而不需要先上传到我的服务器。我不是说现在的做法不好,只是对开发者来说,特别是像可暂停上传这样的功能,客户端直接上传功能会更好。
作为一名重视提升开发体验的工具的开发者,这里有一些推荐。
// Supabase示例代码 const { error, data } = await pinata.upload.file(file); if (error) { throw new PlatformError("Pinata文件上传失败了。"); }
全屏 退出全屏
我独自一人完成了这个挑战。
我使用了一个开源的Shadcn模板作为基础,具体来说,我使用了来自uploader.sadmn.com的上传对话框功能来处理资产的上传。应用程序的其余部分都是我一个人完成的。这个模板只贡献了不到整体代码库2%的代码。
这个挑战既不激烈也不太有挑战性,但非常有教育意义。我学到了很多关于文件的知识,以及如何考虑用户体验的方法。今天的分享就到这里啦!敬请期待更多的更新,继续打造超棒的应用程序吧!🚀✨
祝你编程愉快!😊