如何在SvelteKit的page.server.ts中通过Node.js SDK上传文件到Cloudinary
在SvelteKit后端通过Cloudinary Node.js SDK上传文件(非Base64/前端直传)
前置准备
- 确保已安装Cloudinary SDK:
npm install cloudinary - 在SvelteKit项目根目录创建
.env文件,填入Cloudinary凭证:CLOUDINARY_CLOUD_NAME=你的云名称 CLOUDINARY_API_KEY=你的API密钥 CLOUDINARY_API_SECRET=你的API密钥密码
前端表单修正(page.svelte)
原表单存在标签未闭合、用户无法触发文件选择的问题,调整后代码如下:
<form method="post" enctype="multipart/form-data" use:enhance action="?/upload" > <input class="hidden" name="image" id="file-to-upload" type="file" accept=".png,.jpg" on:change={() => this.form.submit()} /> <button class="border bg-orange-400 rounded py-2 text-sm" type="button" onclick={() => document.getElementById('file-to-upload')?.click()} > Upload! </button> </form>
- 点击按钮会触发隐藏的文件选择框
- 选择文件后自动提交表单,配合
use:enhance实现无刷新提交
后端上传逻辑实现(+page.server.ts)
核心是将FormData中的文件流转换为Node.js兼容流,通过Cloudinary的upload_stream完成上传,同时用Promise包装回调逻辑适配async/await:
import { v2 as cloudinary, type UploadApiResponse } from 'cloudinary'; import { Readable } from 'stream/web'; import { CLOUDINARY_CLOUD_NAME, CLOUDINARY_API_KEY, CLOUDINARY_API_SECRET } from '$env/static/private'; import type { Actions } from './$types'; // 初始化Cloudinary cloudinary.config({ cloud_name: CLOUDINARY_CLOUD_NAME, api_key: CLOUDINARY_API_KEY, api_secret: CLOUDINARY_API_SECRET }); export const actions = { upload: async ({ request }) => { const formData = await request.formData(); const file = formData.get('image') as File | null; if (!file) { return { success: false, error: '未选择文件' }; } // 将Web标准ReadableStream转换为Node.js可读流 const nodeReadableStream = Readable.fromWeb(file.stream()); // 用Promise包装upload_stream的回调逻辑 const uploadPromise = new Promise<UploadApiResponse>((resolve, reject) => { const uploadStream = cloudinary.uploader.upload_stream( { // 可选配置:自定义上传文件夹、文件格式等 folder: 'sveltekit-uploads', format: file.type.split('/')[1] }, (error, result) => { if (error) { reject(error); } else if (result) { resolve(result); } else { reject(new Error('上传失败,无返回结果')); } } ); // 将文件流管道到Cloudinary上传流 nodeReadableStream.pipe(uploadStream); }); try { const uploadResult = await uploadPromise; return { success: true, data: { url: uploadResult.secure_url, publicId: uploadResult.public_id } }; } catch (error) { console.error('上传错误:', error); return { success: false, error: (error as Error).message }; } } } satisfies Actions;
关键逻辑说明
- 流转换:SvelteKit服务端接收的
File对象返回的是Web标准ReadableStream,通过Readable.fromWeb()转换为Node.js兼容的可读流,才能被Cloudinary的upload_stream消费。 - Promise包装:Cloudinary的
upload_stream基于回调实现,包装为Promise后可以用async/await优雅处理异步结果。 - 错误处理:捕获上传过程中的错误,返回结构化结果给前端,方便页面展示提示。
内容的提问来源于stack exchange,提问作者Alexander Guskov
相关产品推荐
相关产品推荐

