You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Gatsby对接Contentful CMS时富文本内容中图片无法显示问题求助

解决方案

你的问题由两个核心原因导致:

  1. GraphQL查询没有拉取资源的唯一标识ID,无法和富文本中返回的asset ID做匹配
  2. EMBEDDED_ASSET的渲染逻辑没有处理ID和实际资源的匹配关联,仅打印了node原始信息
  3. 补充说明:embedded-asset-block的content字段本身就是空设计,资源关联信息全部存储在data.target.sys.id中,不需要关注该字段为空的问题

第一步:修改GraphQL查询

补充references下的sys.id字段,用于关联匹配,同时可以补充文件名、资源类型字段方便后续使用:

query getThisProjectBySlug($slug: String) {
    allContentfulProject(filter: {slug: {eq: $slug}}) {
      nodes {
        slug
        id
        subtitle
        title
        details {
          raw
          references {
            sys {
              id
            }
            file {
              url
              fileName
              contentType
            }
          }
        }
      }
    }
  }

第二步:修改富文本图片渲染逻辑

重写BLOCKS.EMBEDDED_ASSET的处理函数,匹配对应ID的资源并渲染图片,注意Contentful返回的资源URL默认不带https协议头,需要手动拼接:

const options = {
    renderMark: {
        [MARKS.BOLD]: (text) => <Bold>{text}</Bold>,
    },
    renderNode: {
        [BLOCKS.PARAGRAPH]: (node, children) => <Text>{children}</Text>,
        [BLOCKS.EMBEDDED_ASSET]: node => {
            // 获取当前嵌入资源的ID
            const assetId = node.data.target.sys.id
            // 从返回的资源列表中匹配对应ID的资源
            const targetAsset = details.references.find(asset => asset.sys.id === assetId)
            // 仅当资源存在且为图片类型时渲染
            if (targetAsset?.file?.url && targetAsset.file.contentType.startsWith('image/')) {
                return <img 
                  src={`https:${targetAsset.file.url}`} 
                  alt={targetAsset.file.fileName} 
                  style={{maxWidth: '100%', margin: '16px 0'}} 
                />
            }
            return null
        },
    },
};

修改后完整代码

import React from 'react'
import { graphql } from 'gatsby'
import Layout from '../../components/layout'
import { renderRichText } from "gatsby-source-contentful/rich-text"
import { BLOCKS, MARKS } from '@contentful/rich-text-types';

export default function ProjectDetails({ data, location }) {

    const { title, subtitle, details } = data.allContentfulProject.nodes[0]

    const Bold = ({ children }) => <span className="bold">{children}</span>;

    const Text = ({ children }) => <p className="align-center">{children}</p>;

    const options = {
        renderMark: {
            [MARKS.BOLD]: (text) => <Bold>{text}</Bold>,
        },
        renderNode: {
            [BLOCKS.PARAGRAPH]: (node, children) => <Text>{children}</Text>,
            [BLOCKS.EMBEDDED_ASSET]: node => {
                const assetId = node.data.target.sys.id
                const targetAsset = details.references.find(asset => asset.sys.id === assetId)
                if (targetAsset?.file?.url && targetAsset.file.contentType.startsWith('image/')) {
                    return <img 
                      src={`https:${targetAsset.file.url}`} 
                      alt={targetAsset.file.fileName} 
                      style={{maxWidth: '100%', margin: '16px 0'}} 
                    />
                }
                return null
            },
        },
    };

    return (
        <Layout>
            <div>
                <h1>{title}</h1>
                <h2>{subtitle}</h2>
                <p>{renderRichText(details, options)}</p>
            </div>
        </Layout>
    )
}

export const query = graphql`
query getThisProjectBySlug($slug: String) {
    allContentfulProject(filter: {slug: {eq: $slug}}) {
      nodes {
        slug
        id
        subtitle
        title
        details {
          raw
          references {
            sys {
              id
            }
            file {
              url
              fileName
              contentType
            }
          }
        }
      }
    }
  }
`

内容的提问来源于stack exchange,提问作者KylianMbappe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 00:27:05