Next.js元标签开发环境正常生产环境失效问题及解决
生产环境下Next.js页面OG/Twitter元标签无法被Facebook/Twitter工具识别的解决方法
问题概述
我负责的项目包含静态和动态两种页面,开发环境下链接预览功能完全正常,已经通过本地的Open Graph检测工具、Twitter及Facebook分享调试工具验证过。但部署到生产环境后,Facebook调试工具和Twitter卡片验证工具无法正确识别页面的元标签。
代码示例
静态页NextSeo实现
<> <NextSeo title="FAQ - OpenLinks - Just Another Link in Bio tool" description="Get your answers for some common and most asked questions at OpenLinks." additionalMetaTags={[ { name: "keywords", content: "OpenLinks faq,OpenLinks questions,OpenLinks common questions", }, { name: "author", content: "Jayant Navrange", }, ]} openGraph={{ url: "https://openlinks.vercel.app/faq", title: "FAQ - OpenLinks", type: "website", description: "Get your answers for some common and most asked questions at OpenLinks.", images: [ { url: "https://openlinks.vercel.app/favicon-310.png", width: 200, height: 200, alt: "Website Logo", }, ], siteName: "OpenLinks", }} twitter={{ cardType: "summary", }} /> </>
动态页NextSeo实现
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction import Image from "next/image"; import styles from "../styles/Profile.module.css"; import { getIcon } from "../helpers/util"; import { isValid } from "../helpers/isValid"; import { NextSeo } from "next-seo"; import { JSDOM } from "jsdom"; import DOMPurify from "dompurify"; import Link from "next/link"; import { EmailShareButton, FacebookShareButton, LinkedinShareButton, RedditShareButton, TelegramShareButton, TwitterShareButton, WhatsappShareButton, } from "react-share"; import { EmailIcon, FacebookIcon, LinkedinIcon, RedditIcon, TelegramIcon, TwitterIcon, WhatsappIcon, } from "react-share"; import toast, { Toaster } from "react-hot-toast"; import { Spotify } from "react-spotify-embed"; const youtubeEmbed = require("youtube-embed"); let cnt = 0; const shareOnSM = (urlToShare) => { toast( (t) => ( <div> <h5>Share on</h5> <hr /> <EmailShareButton url={urlToShare}> <EmailIcon size={25} round /> </EmailShareButton> <LinkedinShareButton url={urlToShare}> <LinkedinIcon size={25} round /> </LinkedinShareButton> <TwitterShareButton url={urlToShare}> <TwitterIcon size={25} round /> </TwitterShareButton> <FacebookShareButton url={urlToShare}> <FacebookIcon size={25} round /> </FacebookShareButton> <RedditShareButton url={urlToShare}> <RedditIcon size={25} round /> </RedditShareButton> <WhatsappShareButton url={urlToShare}> <WhatsappIcon size={25} round /> </WhatsappShareButton> <TelegramShareButton url={urlToShare}> <TelegramIcon size={25} round /> </TelegramShareButton> <hr /> <div className="float-end"> <button type="button" className="btn btn-outline-primary" onClick={() => toast.dismiss(t.id)} > Cancel </button> </div> </div> ), { position: "bottom-right", } ); }; export default function SingleData({ id, idAwake, last_login, dname, fname, dp, location, summary, url, pronoun, type, wdata, dpayd, bpayd, miscdata, }) { const convertTime = () => { let d = new Date(last_login); return d.toLocaleTimeString(); }; const createMarkup = (cl) => { return { __html: cl }; }; return ( <> <NextSeo title={ dname === id ? `${dname} at OpenLinks` : `${id} not found at OpenLinks` } description={`${ dname === id ? `This is the profile of ` + dname + ` find every link by this author at OpenLinks` : dname + " The profile of this user not exists at OpenLinks" }`} additionalMetaTags={[ { name: "keywords", content: `${dname} profile, ${dname} openlinks`, }, { name: "author", content: "Jayant Navrange", }, { name: "twitter:title", content: dname === id ? `${dname} at OpenLinks` : `${id} not found at OpenLinks`, }, { name: "twitter:description", content: `${ dname === id ? `This is the profile of ` + dname + ` find every link by this author at OpenLinks` : dname + " The profile of this user not exists at OpenLinks" }`, }, { name: "twitter:image", content: dp, }, ]} openGraph={{ url: `https://openlinks.vercel.app/${dname}`, title: `${dname === id ? dname : `${id} not found`} at OpenLinks`, type: "website", description: `${ dname === id ? `This is the profile of ` + dname + ` find every link by this author at OpenLinks` : dname + " The profile of this user not exists at OpenLinks" }`, images: [ { url: dp, width: 300, height: 157, alt: `Image of user ${dname}`, }, { url: dp, width: 800, height: 600, alt: `Image of user ${dname}`, }, { url: dp, width: 900, height: 800, alt: `Image of user ${dname}`, }, { url: dp, width: 200, height: 200, alt: `Image of user ${dname}`, }, { url: dp }, ], siteName: "OpenLinks", }} twitter={{ cardType: "summary", }} /> --Other contents-- </> ); } export async function getServerSideProps(context) { const { params } = context; const { id } = params; const response = await fetch( `${process.env.NEXT_PUBLIC_FIREBASE_DATABASEURL}/users/${id}/.json` ); const data = await response.json(); const window = new JSDOM("").window; const purify = DOMPurify(window); const summary = purify.sanitize(data && data.summary); const dname = data && data.dname; const fname = data && data.fname; const pronoun = data && data.pronoun; const location = data && data.location; const type = data && data.type; const url = data && data.url; const last_login = data && data.last_login; const dp = data && data.dp; const idAwake = data && data.emailVer; const web = await fetch( `${process.env.NEXT_PUBLIC_FIREBASE_DATABASEURL}/users/${id}/websites.json` ); const wdata = await web.json(); const dpay = await fetch( `${process.env.NEXT_PUBLIC_FIREBASE_DATABASEURL}/users/${id}/digitalPay.json` ); const dpayd = await dpay.json(); const bpay = await fetch( `${process.env.NEXT_PUBLIC_FIREBASE_DATABASEURL}/users/${id}/bankPay.json` ); const bpayd = await bpay.json(); const misc = await fetch( `${process.env.NEXT_PUBLIC_FIREBASE_DATABASEURL}/users/${id}/miscData.json` ); const miscdata = await misc.json(); return { props: { id, idAwake, fname, dname, dp, location, type, url, pronoun, summary, last_login, wdata, dpayd, bpayd, miscdata, }, }; }
解决方案
经过排查处理,以下部署配置可解决该问题:
- Vercel平台:适配页面使用的
getStaticProps或getServerSideProps渲染方式即可,无需额外配置。 - Netlify平台:需遵循官方部署指南,并开启预渲染功能,确保元标签在页面首次加载时就已生成。
内容的提问来源于stack exchange,提问作者Jayant Navrange
相关产品推荐
相关产品推荐

