Endpoints / API 路由
本教程共 56 篇 · 第 34 篇 · 更新于 2026-08-07 · 约 9 分钟阅读
本节目标:学会用 Astro 的端点(Endpoint)生成静态数据文件,或写出能在服务端处理请求的真实 API。
上一章我们讲的是”Astro 去别的接口要数据”。这一章反过来:让你的 Astro 项目自己成为接口,对外提供数据或处理请求。在 Astro 里,这件事靠**端点(Endpoint)**完成。端点既可以生成静态文件,也能当成一个真正的服务端 API 路由(API Route)。
什么是端点
**端点(Endpoint)**就是放在 src/pages/ 目录下的 .js 或 .ts 文件。它导出一个函数(通常是 GET),返回一个标准的 Response 对象。Astro 会在合适的时候调用它,把你返回的内容变成浏览器能访问的地址。
它和 .astro 页面很像,都放在 pages 里、都能被访问;但端点不返回 HTML 页面,而是返回数据(JSON、图片、文本等)。你可以拿它来:
- 生成一个
sitemap.xml或data.json之类的静态文件; - 做一个 RSS 订阅源;
- 写成一组 API,让前端或别的程序来调用。
Note文件名里的扩展名会被去掉,换成你想要的扩展名。比如
src/pages/data.json.ts构建后访问地址是/data.json。所以写端点时,文件名要带”最终想要的后缀”。
静态文件端点
最基础的用法:在 pages 里建一个 .ts 文件,导出一个 GET 函数,返回一个 Response。
// src/pages/builtwith.json.ts
// 构建后访问:/builtwith.json
export function GET({ params, request }) {
return new Response(
JSON.stringify({
name: "Astro",
url: "https://astro.build/",
})
);
}
在静态站点里,这个函数在构建时被调用一次,返回的内容直接写成 /builtwith.json 文件。访客访问时拿到的就是构建好的那份。
从 Astro v3.0 起,返回的 Response 不再需要写 encoding 字段。所以生成二进制内容(比如图片)也很简单:
// src/pages/astro-logo.png.ts
export async function GET({ params, request }) {
const response = await fetch(
"https://docs.astro.build/assets/full-logo-light.png"
);
return new Response(await response.arrayBuffer());
}
如果你想写类型更安全的端点,可以用 APIRoute 类型配合 satisfies:
import type { APIRoute } from "astro";
export const GET = (async ({ params, request }) => {
// ...
}) satisfies APIRoute;
Tip带文件后缀的端点(如
sitemap.xml.ts)只能用”不带斜杠”的地址访问,比如/sitemap.xml,跟你build.trailingSlash怎么配置无关。这是个小坑,部署后记得用对的地址测一下。
动态路由的端点
端点也支持动态路由(dynamic routing)——就是文件名用方括号包住参数,再导出 getStaticPaths() 列出所有可能的值。
// src/pages/api/[id].json.ts
import type { APIRoute } from "astro";
const usernames = ["Sarah", "Chris", "Yan", "Elian"];
export const GET = (({ params, request }) => {
const id = Number(params.id);
return new Response(
JSON.stringify({
name: usernames[id],
})
);
}) satisfies APIRoute;
export function getStaticPaths() {
return [
{ params: { id: "0" } },
{ params: { id: "1" } },
{ params: { id: "2" } },
{ params: { id: "3" } },
];
}
构建时,它会一次性生成四个 JSON:/api/0.json、/api/1.json、/api/2.json、/api/3.json。逻辑和页面的动态路由完全一样。在静态模式下,你还能通过 getStaticPaths() 给端点传 props;但到了按需渲染模式,端点是个函数不是组件,就不支持传 props 了。
服务端端点(API 路由)
上面都是静态的。一旦你开启按需渲染(第 36 章),端点就升级成”活的”服务端端点:每次收到请求才执行。这下它能干的事一下子多起来——收表单、查数据库、按条件返回不同结果,而且敏感代码只在服务器跑,不暴露给浏览器。
在 server 模式下,路由默认就是按需渲染的。在 static 模式下,你得给端点单独加一句 export const prerender = false 让它走服务端。
服务端端点能直接用 params,不用导出 getStaticPaths();还能自由设置状态码和请求头:
// src/pages/[id].json.js
import type { APIRoute } from "astro";
import { getProduct } from "../db";
export const GET = (async ({ params }) => {
const id = params.id;
const product = await getProduct(id);
if (!product) {
return new Response(null, {
status: 404,
statusText: "Not found",
});
}
return new Response(JSON.stringify(product), {
status: 200,
headers: {
"Content-Type": "application/json",
},
});
}) satisfies APIRoute;
访问 /helmet.json 时,params.id 就是 "helmet"。能查到就返回商品 JSON 和 200;查不到就返回 404。这正是真实 API 的样子。
支持多种 HTTP 方法
端点不只能处理 GET。你可以导出任意 HTTP 方法 名的函数:POST、PUT、DELETE、PATCH 等等。收到请求时,Astro 看方法名调用对应的函数。还能导出 ALL 来兜底所有没单独定义的方法。
// src/pages/methods.json.ts
import type { APIRoute } from "astro";
export const GET = (({ params, request }) => {
return new Response(JSON.stringify({ message: "This was a GET!" }));
}) satisfies APIRoute;
export const POST = (({ request }) => {
return new Response(JSON.stringify({ message: "This was a POST!" }));
}) satisfies APIRoute;
export const DELETE = (({ request }) => {
return new Response(JSON.stringify({ message: "This was a DELETE!" }));
}) satisfies APIRoute;
export const ALL = (({ request }) => {
return new Response(JSON.stringify({ message: `This was a ${request.method}!` }));
}) satisfies APIRoute;
如果你只定义了 GET 没定义 HEAD,Astro 会自动用 GET 的结果,只把响应体去掉,当作 HEAD 的回复。
Note
HEAD是一种”只要响应头、不要正文”的请求,常用来检查资源是否存在。Astro 帮你自动处理了,省心。
读取请求里的数据
在按需渲染模式下,端点拿到的 request 是一个完整的 Request 对象。你能读请求头、读请求体。下面这个例子处理 POST,从 JSON 请求体里取名字再回传:
// src/pages/test-post.json.ts
import type { APIRoute } from "astro";
export const POST = (async ({ request }) => {
if (request.headers.get("Content-Type") === "application/json") {
const body = await request.json();
const name = body.name;
return new Response(
JSON.stringify({
message: "Your name was: " + name,
}),
{ status: 200 }
);
}
return new Response(null, { status: 400 });
}) satisfies APIRoute;
端点里做重定向
端点上下文还提供了一个 redirect() 工具,和页面里的 Astro.redirect 用法一致。比如根据短链 ID 跳到真实地址:
// src/pages/links/[id].js
import type { APIRoute } from "astro";
import { getLinkUrl } from "../db";
export const GET = (async ({ params, redirect }) => {
const { id } = params;
const link = await getLinkUrl(id);
if (!link) {
return new Response(null, { status: 404, statusText: "Not found" });
}
return redirect(link, 307);
}) satisfies APIRoute;
端点返回的内容不限于 JSON
端点返回什么,全看你构造的 Response。除了 JSON,也能返回纯文本、HTML,甚至图片的二进制数据。比如返回一个简单的 HTML 片段:
// src/pages/hello.ts
import type { APIRoute } from "astro";
export const GET = (async () => {
return new Response("<h1>Hello from endpoint</h1>", {
headers: { "Content-Type": "text/html" },
});
}) satisfies APIRoute;
关键点就一个:通过 Response 的 headers 里的 Content-Type,告诉浏览器”这是什么类型”。设对了,浏览器按对应方式处理;设错了,可能把本该显示的 HTML 当成文件下载下来。
静态端点和服务端端点怎么选
两种端点写法很像,区别在于”什么时候跑”。一句话判断:
- 内容固定、不依赖访客 → 用静态端点,构建时生成一次,省钱又快。比如站点地图、RSS、很少变的配置。
- 内容因人因时而异、要读请求 → 用服务端端点(开按需渲染),每次请求现算。比如用户资料、搜索、表单提交。
在静态模式里,端点拿到的 request 其实只有 request.url 能用——它返回当前端点的完整网址,用法和页面里的 Astro.request.url 一样。真正的请求体、请求头要等到按需渲染才完整可用。
Tip端点文件一旦带
.json、.xml这类后缀,访问地址就不能带结尾斜杠。比如sitemap.xml.ts只能以/sitemap.xml访问。部署后拿这个地址测一下,别被斜杠坑了。
端点也要优雅地处理错误
服务端端点跑在真实流量下,出错概率比构建时高不少。别让一个没兜住的异常变成 500 白页。下面这个例子在取数失败时返回 500 和一句人话:
// src/pages/api/product.ts
import type { APIRoute } from "astro";
export const GET = (async ({ params }) => {
try {
const product = await getProduct(params.id);
if (!product) {
return new Response("找不到该商品", { status: 404 });
}
return new Response(JSON.stringify(product), {
status: 200,
headers: { "Content-Type": "application/json" },
});
} catch (err) {
return new Response("服务暂时不可用", { status: 500 });
}
}) satisfies APIRoute;
返回什么状态码,最好和语义对上:找不到是 404、参数不对是 400、服务器自己崩了是 500。前端或别的程序调用你的端点时,正是靠这些码来判断下一步怎么走。状态码给得准,调用方才好写逻辑。
小结
端点就是 pages 里的 .js/.ts 文件,导出一个 GET(或别的 HTTP 方法)函数,返回一个 Response。静态模式下它在构建时跑一次、生成文件;按需渲染模式下它变成活的 API 路由,能收请求、读请求体、设状态码、做重定向。动态路由、多方法、重定向都支持。
下一章我们聊环境变量,它是存放接口密钥、切换开发/生产配置的必备工具。先把端点想成”返回数据的页面”,静态给文件、按需给 API,就不容易迷路。