Simba
Simba
HTML

了解Open Graph:优化你的网站在社交媒体上的分享

了解Open Graph:优化你的网站在社交媒体上的分享
10 min read
#html

最近在X上分享了个自己博客的链接,发现和平常看到很多大佬分享的博客链接相比显得非常朴素。一开始我以为是开通了Premium的原因hhh,直到我翻 Next.js API Reference 时,发现了关于MetaData Files的 opengraph-image 介绍才恍然大悟🫨,同时发现是个很有趣的东西,听我细嗦🤗。

Open Graph 快速通关 ⚔️

什么是Open Graph 🤔️

Open Graph 是一种由Facebook引入的元数据协议,旨在标准化网页上的元数据信息,以便在社交媒体平台上分享时更好地呈现。通过使用Open Graph标签,您可以控制分享时显示的标题、摘要、图像等关键信息,使您的内容在社交媒体上更具吸引力。

大白话:在一些主流的社交媒体美化你分享的链接,呈现更好的预览效果。(微信小程序分享

如何使用Open Graph 🤔️

使用Open Graph非常简单,只需在网页的头部插入一些HTML标签。以下是一些基本的Open Graph标签:

<meta property="og:title" content="您的标题">
<meta property="og:description" content="您的描述">
<meta property="og:image" content="您的图像链接">
<meta property="og:url" content="您的网页链接">

强烈建议首次使用时阅读更完整的协议内容,说不定你会发现更拓展你需求的MetaData 🤗 Open Graph Protocol

整理需求 📝

添加Open Graph是简单的,只需要在html中加入meta选项。但在实现的过程中,你需要确定:

  • ⚠️ 请注意,Open Graph的og:image属性需要接受一个绝对路径的地址。
    • 理论上可以接受相对路径,但这会依赖于社交媒体平台如何解析和处理这些路径。大多数情况下,为确保最佳兼容性,建议使用绝对路径。
  • 如果你需要的只是一张静态资源的图片(比如你只是想将博客的封面图作为分享的图片。
    • 这时你只需要在获取博客详情时,动态添加相关的内容到多个<meta>标签中。
  • 如果你需要根据文章的标题 / 内容生成一张动态的og:image地址。
    • 那你需要有一定的后端知识,搭建一个能返回支持定制化的图片接口。

这些都是你在添加Open Graph时需要思考的事情,这决定了你的实现方式以及难易度的不同。以下我会用根据博客标题动态生成Open Graph图片链接的方式来举例。

技术方案 😇

需求确定了,但在这里的技术选型时,我纠结于是否使用Node.js去实现这样一个根据携带参数绘制Canvas并生成图片的接口,具体考虑如下😇:

  • 优点:可定制化高。Canvas API不用黑的是它的绘图能力,可以通过自定义各种图形、文本等元素,实现丰富的图像效果。
  • 缺点:
    • 性能开销:动态生成图像可能引起较高的性能开销,绘图操作也会占用较多内存。
    • 额外的交互:因为现在我的博客是Next.jsMarkdown文件进行解析 & 静态托管的,所以在前端需要实现额外的交互逻辑。
    • 难以缓存:我并不想这个接口是显性实时请求的,或许得考虑在前端创建博客后就生成动态的图片。但是这个情况有例外,就是在非博客页需要自己手动再去生成og:image,感觉拓展性变差很多,有点本末倒置了😵‍💫

后来想起来在之前使用Next.js的时候,Pages Router模式下有个API Routes的特性,可以实现服务端API的效果。但是它只允许一些简单API的响应,不包括图片😭

然后我又双叒叕想起来自己博客其实是Next.js 13,所以我只能用App Router(但是我没那么喜欢😭👊。然后刚好App Router有个Route Handlers,他是代替以前API Routes的新特性,并且可以包含更多响应类型,包括ImageResponse对象,可以使用定义tsx的方式来生成图片!!!因祸得福了属于是🤡。

最后的方案确定成了:Route Handlers + GenerateMetadata(说在前面,它并没有比Node.js的方案在性能上好到哪里去,它最大的优点是省事😬。)

生成动态Open Graph图片

定义API Route

  1. 创建处理请求Open Graph的handler路由文件 app/api/og.tsx
  2. 因为我这里使用的是GET方式,所以我就让动态标题通过query来传递 & 接收。
  3. 定义一段tsx,描述生成图片的结构。
    • 图片需使用原始<img>标签。
      • ⚠️ 在需要使用到图片的地方都得使用绝对路径。(background-image / <img src="xxx">
    • 使用Tailwind CSS定义样式,给元素添加tw属性即可。
    • 直接修改style属性同样可以生效。
    • 部分样式在ImageResponse中会失效。
  4. 返回Next.js提供的ImageResponse实例化对象。

(如果需要修改字体,可以参照ImageResponse文档中的第二个参数进行修改。)

Talk is cheap, show me the code 🤗

// app/api/og.tsx
import { ImageResponse, NextRequest } from 'next/server'
 
export const runtime = 'edge'
 
export async function GET(request: NextRequest) {
  const { searchParams } = new URL(request.url)
  const hasTitle = searchParams.get('title')
  const title = hasTitle
    ? hasTitle.slice(0, 50) // limit title length
    : siteMetadata.title
  
  return new ImageResponse(
    (
      <div
        tw='h-full w-full flex flex-col justify-center py-10 px-20 text-white'
        style={ {
          backgroundImage: `url(${/* your background image */})`,
          backgroundSize: '100% 100%',
        } }
      >
        <div
          tw='text-6xl font-bold'
        >
          { title }
        </div>
        <div
          tw='text-2xl mt-4 tracking-wider font-semibold'
        >
          @Simba.Wang {/* your name */}
        </div>
      </div>
    ),
    {
      width: 1200,
      height: 630,
    },
  )
}

在本地生成一个标题为「Hello-Word」的Open Graph Image,测试下你的API吧:http://127.0.0.1:3000/api/og?title=Hello-World (链接需根据自身情况修改

在页面中生成meta标签

到了这一步就没啥难点啦 只需要定义页面的generateMetadata,组装你想描述的meta即可.我用我自己博客标签页的generateMetadata抛砖引玉一下:

// app/categories/[slug]/page.tsx
import { siteMetadata } from '../../../utils/siteMetaData'; // replace to your site meta data
 
export async function generateMetadata({ params }: { params: { slug: string } }) {
	const title = params.slug.toUpperCase()
	const description = `Learn more about ${params.slug} | Simba's Blog`
	const openGraphTitle = `Category — ${title}`
 
	return {
		description,
		title: `#${title}`,
		openGraph: {
			description,
			title: openGraphTitle,
			url: `${siteMetadata.siteUrl}/categories/${params.slug}`,
			siteName: siteMetadata.title,
			type: "article",
			authors: [siteMetadata.author],
			images: [
				{
					url: `${siteMetadata.siteUrl}/api/og?title=${openGraphTitle}`,
				},
			],
		},
		twitter: {
			description,
			title: openGraphTitle,
			card: "summary_large_image",
			images: [
				`${siteMetadata.siteUrl}/api/og?title=${openGraphTitle}`,
			],
		}
	};
}

这里需要注意的一点是:当 openGraphTitle 更改时,就意味着 meta 标签的 URL 会发生更改,但社交平台并不会实时更新 meta 标签渲染的内容。比如 Twitter Cards 就有相关的更新规定,他们会在每 7 天重新建立索引,所以你的 meta 标签更新的渲染内容需要在 7 天后才能看到。

The Twitter web crawler re-indexes the Card tag information on your page roughly every seven days.

具体可以查看社交平台文档所支持的 Open Graph 属性来定义。同时也有需要额外自定义 meta 标签属性的平台,比如 Twitter Cards

最后放一张我博客里 Tailwind CSS - 非常值得一试的CSS框架 链接的Twitter Card效果图。动手来试试吧!!!🤗

twitter-card