如何在前端(React)中实现 Cloudinary 大文件分片直传

9次阅读

如何在前端(React)中实现 Cloudinary 大文件分片直传

本文详解如何在 react 应用中不依赖 cloudinary 前端 widget 或 jquery sdk,直接通过原生 javascript 调用 cloudinary rest api 实现大文件(>100mb)的无后端中转、分片上传,支持 unsigned 与 signed 两种安全模式。

Cloudinary 官方 node.js 后端 SDK(如 cloudinary.v2.uploader.upload_stream 和 upload_large_stream)虽内置完善的流式分片逻辑,但因其强依赖 Node.js 运行时(如 fs, stream, Buffer),无法在浏览器环境中运行。因此,前端需绕过 SDK,采用标准 http 请求 + 分片协议,直接对接 Cloudinary 的 Upload API

✅ 核心方案:纯前端分片上传(Chunked Upload)

Cloudinary 原生支持客户端分片上传(Chunked Upload),无需任何 SDK。其流程如下:

  1. 初始化上传会话:向 https://api.cloudinary.com/v1_1//auto/upload 发起 POST,携带 upload_preset(unsigned)或签名参数(signed),获取 upload_id;
  2. 分片上传:将文件按 chunk_size(推荐 5–20 MB)切片,逐个调用 PUT /v1_1//auto/upload/,附带 Content-Range 头;
  3. 完成上传:发送最终 POST 请求确认上传完成,返回资源 URL。

以下为 react 中的精简实现示例(使用 fetch + AbortController):

// utils/cloudinaryUpload.ts export const uploadLargeFile = async (   file: File,   cloudName: string,   uploadPreset: string,   signatureEndpoint?: string // 可选:后端签名接口 ): Promise<{ secure_url: string; public_id: string }> => {   const chunkSize = 10 * 1024 * 1024; // 10MB/chunk   const totalChunks = Math.ceil(file.size / chunkSize);   let uploadId: string;    // Step 1: 初始化上传(unsigned 或 signed)   const initPayload = { upload_preset: uploadPreset };   if (signatureEndpoint) {     const { timestamp, signature } = await fetch(signatureEndpoint, {       method: 'POST',       body: JSON.stringify({ file_size: file.size, file_type: file.type }),     }).then(r => r.json());     Object.assign(initPayload, { timestamp, signature, api_key: 'YOUR_API_KEY' });   }    const initRes = await fetch(     `https://api.cloudinary.com/v1_1/${cloudName}/auto/upload`,     { method: 'POST', body: JSON.stringify(initPayload) }   );   const initJson = await initRes.json();   uploadId = initJson.upload_id;    // Step 2: 分片上传   for (let i = 0; i < totalChunks; i++) {     const start = i * chunkSize;     const end = Math.min(start + chunkSize, file.size);     const chunk = file.slice(start, end);     const blob = new Blob([chunk], { type: file.type });      await fetch(       `https://api.cloudinary.com/v1_1/${cloudName}/auto/upload/${uploadId}`,       {         method: 'PUT',         headers: {           'Content-Range': `bytes ${start}-${end - 1}/${file.size}`,           'Content-Type': file.type,         },         body: blob,       }     );   }    // Step 3: 完成上传   const completeRes = await fetch(     `https://api.cloudinary.com/v1_1/${cloudName}/auto/upload/${uploadId}`,     { method: 'POST' }   );   return completeRes.json(); };  // 在组件中调用 function UploadButton() {   const handleUpload = async () => {     const file = document.querySelector('input[type="file"]')?.files?.[0];     if (!file) return;      try {       const result = await uploadLargeFile(         file,         'your_cloud_name',         'your_upload_preset',         '/api/cloudinary/sign' // 若启用 signed 上传       );       console.log('Upload success:', result.secure_url);     } catch (err) {       console.error('Upload failed:', err);     }   };    return (     <>                      ); }

⚠️ 关键注意事项

  • Unsigned 上传限制:仅允许预设白名单中的参数(如 folder, tags, context),且禁止设置 public_id 或 overwrite;适合公开、低敏感场景。
  • Signed 上传更安全:需后端生成签名(基于 api_secret + 参数排序 + SHA1),可完全控制上传行为(如强制 public_id、resource_type、eager 转码等)。签名逻辑示例(node.js):
    // POST /api/cloudinary/sign app.post('/sign', (req, res) => {   const { file_size, file_type, ...rest } = req.body;   const timestamp = Math.floor(Date.now() / 1000);   const params = { timestamp, file_size, file_type, ...rest };   const sorted = Object.keys(params)     .sort()     .map(k => `${k}=${params[k]}`)     .join('&');   const signature = crypto     .createHash('sha1')     .update(sorted + process.env.CLOUDINARY_API_SECRET)     .digest('hex');   res.json({ timestamp, signature, api_key: process.env.CLOUDINARY_API_KEY }); });
  • 错误重试与断点续传:生产环境应添加 fetch 重试机制、AbortController 中断支持,并持久化 upload_id 与已上传分片索引,实现断点续传。
  • CORS 配置:确保 Cloudinary 域名(api.cloudinary.com)已在 Cloudinary 控制台的 Settings → Security → CORS 中正确配置允许的前端域名。

✅ 总结

放弃“复用后端 SDK”的思路,转而采用 Cloudinary 原生 Chunked Upload API,是 React 等现代前端框架实现大文件直传的最佳实践。它轻量、可控、符合安全规范,且完全规避了服务端带宽与内存瓶颈。结合 signed 上传与后端签名服务,即可在保障灵活性的同时满足企业级安全审计要求。

立即学习前端免费学习笔记(深入)”;

text=ZqhQzanResources