个人博客想提高SEO,用 Next.js 把前端做成服务端渲染

举报
海是岛思念的泪 发表于 2026/09/08 09:41:07 2026/09/08
【摘要】 纯前端 SPA 首屏白屏、搜索引擎抓不到内容。用 Next.js 的 SSR/SSG 把页面在服务端渲染成完整 HTML,爬虫友好、首屏更快,这篇从路由到数据获取讲透。

早些年用 Vue / React 直接做SPA(单页应用),生态丰富,开发确实快速方便,但上线后问题来了:搜索引擎抓到的永远是一句"Loading…",社交平台分享出来的卡片也是空的,首屏还得等 JS 下载完才能看到字。做内容型站点(博客、文档、商城详情页)这种代价扛不起。Next.js 就是为了解决这个问题而生的——它在服务端把页面渲染成完整 HTML,既保留 React 的开发体验,又让首屏和 SEO 都正常。这篇我用做一个博客站点的例子,把 SSR 到底怎么回事、怎么取数据、怎么上线,讲清楚。

image.png

一、先说清楚 CSR 的痛点

传统 SPA 的流程是:浏览器先下载一个几乎空的 HTML,再下载一大坨 JS,JS 跑起来后才去请求接口、渲染内容。问题就出在这:

  • SEO 不友好:爬虫拿到的是空壳,很多搜索引擎不会等 JS 执行完。
  • 首屏慢:弱网环境下,用户盯着白屏好几秒。
  • 社交分享丑:Open Graph 抓取不到正文,分享出去是个没图的链接。

而 SSR(服务端渲染)是:用户请求一个 URL,服务器当场把组件渲染成 HTML 字符串返回,浏览器拿到就能直接显示文字,JS 再"注水"让页面可交互。首屏内容和 SEO 问题一并解决。

二、Next.js 怎么把活挪到服务端

Next.js(App Router 写法)里,组件默认就在服务端运行。要取数据,直接在组件里 await 一个异步函数就行,不用像 SPA 那样在 useEffect 里发请求:

// app/posts/[id]/page.tsx
async function getPost(id: string) {
  const res = await fetch(`https://api.example.com/posts/${id}`, { cache: 'no-store' });
  return res.json();
}

export default async function PostPage({ params }: { params: { id: string } }) {
  const post = await getPost(params.id);   // 服务端直接拿到数据
  return (
    <article>
      <h1>{post.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.content }} />
    </article>
  );
}

这里有个关键点:fetch 默认会被 Next.js 缓存。如果是实时数据,要显式加 cache: 'no-store'(或用 revalidate 控制多久刷新一次),否则你改了内容页面还是旧的——这是新手最常见的"我更新了怎么没变"的原因。

三、渲染策略别只用一种

Next.js 提供了三种渲染方式,按需求选,不是所有页都要 SSR:

方式 触发时机 适合 优点
SSG(静态生成) 构建时生成 博客文章、文档 最快、可 CDN 缓存
SSR(动态渲染) 每次请求 个性化首页、实时数据 内容总是新
CSR(客户端) 浏览器内 登录后dashboard 交互重、无需SEO

博客的文章页其实最适合 SSG:内容不常变,构建时生成好静态 HTML,访问飞快还能上 CDN。写法是在组件里加:

export const revalidate = 3600;   // 最多每小时重新生成一次

这样既不是纯静态死板,也不是每次请求都查库,平衡得很好。

四、路由和元信息

动态路由我们已经用 app/posts/[id]/page.tsx 演示了,路径里的 [id] 就是占位符。SEO 方面,Next.js 提供了专门的 generateMetadata 来输出 <title><meta>,比在 SPA 里用插件注入干净得多:

import { Metadata } from 'next';

export async function generateMetadata({ params }: { params: { id: string } }): Promise<Metadata> {
  const post = await getPost(params.id);
  return {
    title: post.title,
    description: post.summary,
    openGraph: { title: post.title, images: [post.cover] },
  };
}

这段代码保证每个文章页都有独立的标题和分享图,社交平台抓出来就是带封面的漂亮卡片。

五、上线前的几个注意点

  1. 图片用 next/image:它会自动做懒加载、压缩、按设备出不同尺寸,比手写 <img> 省带宽。
  2. API 要同源或配代理:服务端渲染时 fetch 走的是服务器网络,跨域策略和浏览器不一样,注意接口地址别写相对路径导致服务器侧解析错。
  3. 错误边界:用 error.tsxnot-found.tsx 兜住渲染异常,别让一个接口挂了整页白屏。
  4. 构建产物next build 后,next start 起生产服务,或者直接部署到支持 Node 的云平台。

收尾

把前端做成 SSR,本质是把"渲染"这一步从浏览器挪到服务器,换来了首屏速度和搜索可见性。对内容站来说,这笔交换非常划算。Next.js 把路由、数据获取、元信息、缓存策略都封装得很顺手,你只要按"哪类页面用哪种渲染"去分配,就能在开发体验和上线效果之间拿到平衡。后面想再进一步,可以接 ISR(增量静态再生成)做大流量站,或者把评论、点赞这类强交互部分用客户端组件隔离——但那是锦上添花,地基就是这篇讲的 SSR/SSG 思路。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。