基于Next.js的Contentful博客:如何在Rich Text中使用Cloudinary图片替代默认Insert Media功能
我刚好折腾过类似的需求,给你几个实打实可行的方案,你可以根据自己的技术能力和团队的编辑习惯来选:
这是最贴合你需求的方式——直接在Contentful的Rich Text工具栏上加一个「插入Cloudinary图片」的按钮,编辑体验和原生的「Insert Media」完全一致。具体步骤:
第一步:开发自定义上传组件
用React写一个小组件,集成Cloudinary的Upload Widget(或者直接调用Cloudinary的上传API),实现上传图片后生成符合Contentful Rich Text格式的节点(可以自定义一个节点类型,比如custom-cloudinary-image,也可以复用embedded-asset-block结构,把Cloudinary的public_id、alt文本、变换参数存在节点的data里)。第二步:打包成Contentful UI Extension
按照Contentful的扩展规范,创建extension.json配置文件,指定这个扩展是Rich Text的工具栏按钮,然后把组件打包成静态资源(可以部署到Vercel、Netlify或者直接用Contentful的托管)。第三步:在Contentful后台配置
进入Contentful的「Settings」→「Extensions」,导入你的扩展,然后关联到博客文章的Rich Text字段上。之后编辑文章时,工具栏就会出现你自定义的按钮,点击就能直接上传并插入Cloudinary图片到Rich Text里。第四步:前端渲染适配
用@contentful/rich-text-react-renderer渲染时,自定义renderNode规则,识别你插入的Cloudinary节点,转换成Next.js的Cloudinary图片组件(比如用next-cloudinary的CldImage,自动做图片优化)。示例代码:import { documentToReactComponents } from '@contentful/rich-text-react-renderer'; import { CldImage } from 'next-cloudinary'; const richTextRenderOptions = { renderNode: { 'custom-cloudinary-image': (node) => { const { publicId, alt, width, height } = node.data; return ( <CldImage src={publicId} alt={alt || 'Blog post image'} width={width || 800} height={height || 500} sizes="100vw" quality="auto" /> ); }, }, }; // 在页面组件中使用 export default function BlogPost({ post }) { return documentToReactComponents(post.content, richTextRenderOptions); }
优缺点:完美匹配编辑习惯,但需要一点前端开发能力来做扩展,不过Contentful的扩展文档很详细,上手不难。
如果不想折腾开发扩展,这个方案最省事:
- 先把图片上传到Cloudinary控制台,复制它的优化URL(比如带
f_auto,q_auto参数的链接)。 - 在Contentful的Rich Text编辑器里,点击「Embed」→「URL」,粘贴刚才的Cloudinary链接。
- 前端渲染时,自定义Rich Text的渲染规则,识别Cloudinary的URL,把它转换成图片组件而不是普通链接。比如:
const richTextRenderOptions = { renderNode: { 'hyperlink': (node) => { const url = node.data.uri; if (url.includes('res.cloudinary.com')) { // 提取public_id(可以根据你的Cloudinary URL结构调整) const publicId = url.split('/').pop().split('.')[0]; return <CldImage src={publicId} alt={node.content[0].value} />; } // 非Cloudinary链接正常渲染 return <a href={url}>{node.content[0].value}</a>; }, }, };
优缺点:不用写任何扩展,5分钟就能搞定,但编辑时需要多一步手动上传到Cloudinary,效率偏低,适合文章数量不多的情况。
如果想让编辑者继续用原生的「Insert Media」,但自动把Contentful的图片同步到Cloudinary并替换链接,可以用Webhook实现:
- 在Cloudinary创建服务器端上传的API密钥,在Contentful创建一个Webhook,触发条件是博客文章条目创建或更新时,发送请求到你的Next.js API路由(或者单独的Node.js服务)。
- 你的API服务接收到Webhook请求后,解析Rich Text里的Contentful媒体链接,下载图片,上传到Cloudinary,然后把Rich Text里的原始链接替换成Cloudinary的URL,再调用Contentful的API更新文章条目。
- 前端渲染时完全不用改,因为Rich Text里的链接已经是Cloudinary的了。
优缺点:编辑者完全不用改习惯,但需要维护一个后台服务处理同步,还有一定的延迟(因为要等同步完成),适合有开发能力且编辑流程不能变的场景。
内容的提问来源于stack exchange,提问作者Fenwick17

