数据获取
本教程共 56 篇 · 第 33 篇 · 更新于 2026-08-07 · 约 8 分钟阅读
本节目标:搞懂 Astro 怎么在组件里抓取远程接口数据,并把它变成页面里看得见的内容。
做一个网站,光写死文字往往不够。你可能想显示天气、最新文章列表,或者从某个后台拉来的商品信息。这些”别人家的数据”不会凭空出现在你的网页上,得由代码去”取”。在 Astro 里,这件事叫数据获取(Data Fetching)——也就是让你的组件主动去远程接口要数据。
什么是数据获取
简单说,数据获取就是让 Astro 组件在生成页面之前,先去一个网址(通常是 API,也就是”应用程序接口”)把数据”搬”回来。搬回来之后,再用模板语法把它显示成 HTML。
Astro 的 .astro 文件分为两半:上面 --- 之间叫组件脚本,下面叫模板。数据获取就写在上面的脚本里。拿回来之后,在下面模板里用 { } 把值插进去。
NoteAPI 可以理解成”网站之间的取货窗口”。你给它一个网址和参数,它就返回一段数据(通常是 JSON 格式)。
fetch()就是浏览器和 Node 都支持的”去取货”工具。
在 Astro 组件里用 fetch()
所有 Astro 组件都能在脚本里直接用全局的 fetch() 函数。它和你在浏览器里用的 fetch() 是同一个东西。下面这个例子去一个随机用户接口拿数据:
---
// src/components/User.astro
import Contact from "../components/Contact.jsx";
import Location from "../components/Location.astro";
const response = await fetch("https://randomuser.me/api/");
const data = await response.json();
const randomUser = data.results[0];
---
<h1>User</h1>
<h2>{randomUser.name.first} {randomUser.name.last}</h2>
<Contact client:load email={randomUser.email} />
<Location city={randomUser.location.city} />
这里有两个关键点。
第一,脚本里用了 await。Astro 组件脚本支持顶层 await(top-level await),也就是不用包在 async 函数里就能直接 await 一个异步操作。所以 await fetch(...) 写起来很自然。
第二,取回来的数据既能显示在页面上,也能当属性传给别的组件。上面把邮箱传给了 Contact,把城市传给了 Location。这正是 Astro 推荐的思路:数据在 .astro 里取一次,再分发给下面的子组件。
Tip在构建时(build time)取数据,页面生成后就固定了。只有当你开启按需渲染(见第 36 章),
fetch()才会在每次有人访问页面时重新执行,拿到”此刻最新”的数据。
获取数据的时机:构建时还是请求时
这点很重要,新手容易迷糊。
默认情况下(静态站点),Astro 在构建时就把 fetch() 跑完,把结果写进 HTML 文件。网站部署后,访客拿到的是已经写好的静态页面,不会再跑 fetch()。
如果你开启了按需渲染(SSR),那 fetch() 会在每次请求时执行。访客每次刷新,都可能拿到新数据。两种没好坏之分,看你需不需要”实时”。
举个例子:一个博客的作者列表,几天不变,构建时取一次就够了。一个股票行情页,必须请求时取,否则永远是旧价格。
在框架组件里取数据
如果你用了 React、Vue、Svelte 这类”框架组件”(framework components),fetch() 同样能直接在它们的脚本里用:
// src/components/Movies.tsx
import type { FunctionalComponent } from 'preact';
const data = await fetch('https://example.com/movies.json')
.then((response) => response.json());
const Movies: FunctionalComponent = () => {
return <div>{JSON.stringify(data)}</div>;
};
export default Movies;
注意一个细节:构建时渲染的组件,日志会打印在命令行里;如果这个组件带了 client:* 客户端指令(说明它要在浏览器里”水合”运行),日志还会出现在浏览器控制台。
用 GraphQL 查询数据
除了普通的 JSON 接口,很多现代后台(比如内容平台)用 GraphQL。它是一种让你”精确描述想要哪些字段”的查询语言。Astro 照样用 fetch() 去问,只是请求体要写成 GraphQL 的语法。
---
// src/components/Film.astro
const response = await fetch(
"https://swapi-graphql.netlify.app/.netlify/functions/index",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
query: `
query getFilm ($id:ID!) {
film(id: $id) {
title
releaseDate
}
}
`,
variables: {
id: "ZmlsbXM6MQ==",
},
}),
}
);
const json = await response.json();
const { film } = json.data;
---
<h1>Fetching information about Star Wars: A New Hope</h1>
<h2>Title: {film.title}</h2>
<p>Year: {film.releaseDate}</p>
和普通 fetch() 的区别只是:请求方式是 POST,请求体里带上 query 和 variables。返回的数据结构也是你自己定义的,拿起来很清爽。
从无头 CMS 取数据
**CMS(内容管理系统)**是专门用来存内容的地方,比如文章、商品。其中”无头 CMS”只管存和取,不管怎么显示——显示的事交给 Astro。Astro 组件可以像上面一样 fetch() 去 CMS 要数据,再用动态路由(dynamic routes)给每条内容生成独立页面。
官方文档给了不少 CMS 的具体接法,比如 Storyblok、Contentful、WordPress。第 38 章我们会整体聊聊后端和 CMS 怎么和 Astro 配合。这里你只要记住一条思路:CMS 存内容,Astro 去取,取回来渲染成页面。
Tip如果你的内容本来就是 Markdown 文件,其实不用 CMS,Astro 自带的内容集合(content collections)就够用了。CMS 适合”非技术人员也要在后台写内容”的场景。
构建时取数的注意事项
默认静态模式下,fetch() 在构建时只跑一次。这带来几个要留心的地方。
第一,接口必须在构建环境能连通。你的电脑或 CI(持续集成,自动帮你构建的机器)要能访问那个网址。如果接口只在本地才通、或需要登录态,构建就会失败,部署也跟着出问题。
第二,数据”冻结”在构建那一刻。页面生成后内容就固定了,之后接口怎么变,页面都不会自动跟。想让它常新,要么重新构建一次,要么改用按需渲染(第 36 章),让 fetch() 在每次请求时重跑。
第三,做好失败兜底。网络会抖,接口会挂。取数之后判断一下是否为空、是否报错,至少给个默认值,别让整页白屏。下面是个简单的兜底写法:
---
const response = await fetch("https://example.com/api/posts");
const posts = response.ok ? await response.json() : [];
---
<ul>
{posts.map((p) => <li>{p.title}</li>)}
</ul>
把数据传给框架组件时,思路也一致:在 .astro 里取好,再以属性形式传下去,组件自己别重复去取。这样既清晰,又省了重复的请求。
给取数加个超时保护
网络卡不卡、接口半死不活,你控制不了。如果 fetch() 一直等,页面就一直转圈。给请求加一个超时,能避免这种尴尬:
---
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 3000); // 3 秒还没回就放弃
const response = await fetch("https://example.com/api/posts", {
signal: controller.signal,
});
clearTimeout(timer);
const posts = response.ok ? await response.json() : [];
---
AbortController 能在指定时间后主动取消请求。取消后 fetch() 会抛错,配合前面讲过的兜底写法,页面至少能给个空列表,而不是卡死在那里。构建时取数也建议加上,免得某次构建因为接口抽风而失败。
小结
数据获取的核心就三步:在组件脚本里 await fetch() 把数据要回来;在模板里用 { } 显示;需要的话,把数据当属性传给子组件。默认在构建时取一次,开启按需渲染后每次请求都取。JSON 和 GraphQL 都能用,CMS 也是同一个套路。
下一章我们看怎么用”端点(Endpoint)“把你的 Astro 项目变成能对外提供数据的 API。