写给 Python/Go 开发者的前端速通(3):你的 fetch 到底是在哪里发起的?揭秘 Next.js 服务端渲染

在[上一篇文章]中,我们解剖了前端页面组件的“工厂流水线”,并看到了这样一段发起网络请求的核心代码:

// 进货渠道
async function getAthletes(): Promise<Athlete[]> {
  const res = await fetch('http://localhost:8080/api/athletes');
  return res.json() as Promise<Athlete[]>; 
}

// 页面组件
export default async function AthletesPage() {
  const athletes = await getAthletes(); 
  return ( <div>...渲染列表...</div> );
}

代码看懂了,但对于习惯了写后端 API 的 Python/Go 开发者来说,这里藏着一个巨大的盲区,也是现代前端最容易让人懵逼的问题:
这段 fetch 代码,到底是在用户的浏览器(手机/电脑)里执行的,还是在前端的服务器上执行的?

搞懂这个问题,你才算真正跨过了现代前端(React / Next.js)的门槛。今天我们就来把这个“黑盒”彻底打开。


时代眼泪:传统的 CSR(客户端渲染)

如果这段代码放在几年前的传统 React (Create React App) 或 Vue 项目中,它的执行逻辑是这样的(客户端渲染 Client-Side Rendering):

  1. 用户在浏览器输入网址。
  2. 前端服务器直接扔给浏览器一个几乎空白的 HTML 和一个巨大的 JS 文件
  3. 浏览器下载完 JS,开始执行代码。
  4. 浏览器(用户的电脑/手机) 里的 JS 代码发起了 fetch('http://localhost:8080...')
  5. 你的 Go 后端收到请求,返回 JSON。
  6. 浏览器拿到 JSON,用 JS 动态生成 HTML,页面才终于显示出运动员列表。

后端的痛点:

  • 跨域(CORS)地狱:因为是用户的浏览器直接请求你的 Go 服务器,如果域名不同,浏览器会直接拦截,把你折腾得死去活来。
  • 白屏时间长:网速慢的手机上,用户要看很久的“加载中…”。
  • SEO 灾难:百度/谷歌的爬虫拿到的是空白 HTML,根本不知道你的网页里有啥。

降维打击:Next.js 的 RSC(React 服务端组件)

回到我们这套代码!仔细看组件定义:export default async function AthletesPage()
请注意这个 async,在现代的 Next.js(App Router 模式)中,给组件加上 async,意味着它是一个 RSC(React Server Component,服务端组件)

这意味着,这段代码根本不会在用户的浏览器里执行,而是在前端的 Node.js 服务器上执行的!

用后端的视角来看,它完美等价于 Python 的 Jinja2 或者 Go 的 html/template

真实的请求链路是这样的:

  1. 用户在浏览器输入网址。
  2. 前端的 Node.js 服务器 收到请求,开始执行 AthletesPage 函数。
  3. 走到 const athletes = await getAthletes() 时,Node.js 服务器 在内网发起 fetch,向你的 Go 后端(比如跑在同一台机器的 8080 端口)请求数据。
  4. Go 后端秒回 JSON 数据给 Node.js 服务器。
  5. Node.js 服务器拿到数据,立刻在内存里把 <li key={...}> 这些 HTML 标签拼接好
  6. Node.js 把拼接好数据的、完整的、纯静态的 HTML 发送给用户的浏览器。
  7. 浏览器收到 HTML,瞬间显示页面。

💡 为什么这种模式让后端狂喜?

一旦你理解了 getAthletes() 是在前端的 Node.js 服务器上跑的,你就会发现现代前端框架其实是对后端极其友好的:

  1. 没有跨域(CORS)问题了!
    这是 Node.js 服务器和你的 Go 服务器之间的**服务器对服务器(Server-to-Server)**通信。根本不经过浏览器,自然就没有浏览器的同源策略限制,彻底告别 CORS 报错。
  2. 极度安全,可以藏 API Key!
    以前在前端代码里写第三方的 API Key,等于是直接发给用户。现在由于代码在服务端执行,你可以放心地在 fetch 里塞各种带鉴权的 Header,浏览器端抓包绝对抓不到。
  3. 甚至可以直连数据库(如果不写 Go 后端的话)
    因为环境在服务端,很多 Next.js 开发者甚至连外挂后端都省了,直接在这个 getAthletes 函数里写 SELECT * FROM athletes 查询 PostgreSQL 数据库。

总结与预告

前端不再仅仅是运行在浏览器里的一团 JS 脚本,现代的 Next.js 实际上是一个拥有完整服务端能力的框架

通过这三篇帖子,我们从 TypeScript 的“数据图纸”(Interface),讲到组件的“流水线工厂”(Component & Map),再到今天揭开了“前端服务器”(SSR / RSC)的真面目。前端对你来说,应该不再是黑盒了!

当然,前线的网页再花哨,也离不开坚实的后勤保障。下一篇,我们将正式回到我们的主场——深入拆解 Go 后端的四层架构(Handler / Service / Repository / Model),看看如何写出工业级、易扩展的后端 API! 敬请期待!

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐