跳转到内容

端点

Astro 允许你创建自定义端点来提供任何类型的数据。你可以用它来生成图像、提供 RSS 文档,或者将其用作 API 路由来为你的站点构建一个完整的 API。

在静态生成的网站中,你的自定义端点在构建时被调用以生成静态文件。如果你选择进入 SSR 模式,自定义端点会变成实时的服务器端点,在请求时被调用。静态和 SSR 端点的定义方式类似,但 SSR 端点支持更多功能。

要创建一个自定义端点,请在 /pages 目录中添加一个 .js.ts 文件。在构建过程中,.js.ts 扩展名将被移除,因此文件名应包含你想要创建的数据的扩展名。例如,src/pages/data.json.ts 将会构建一个 /data.json 端点。

端点导出一个 GET 函数(可选 async),它接收一个上下文对象,其属性与 Astro 全局对象类似。在这里,它返回一个Response对象,带有 nameurl,Astro 会在构建时调用它,并使用响应体的内容来生成文件。

src/pages/builtwith.json.ts
// Outputs: /builtwith.json
export function GET({ params, request }) {
return new Response(
JSON.stringify({
name: "Astro",
url: "https://astro.js.cn/",
}),
);
}

从 Astro v3.0 开始,返回的 Response 对象不再需要包含 encoding 属性。例如,要生成一个二进制的 .png 图像:

src/pages/astro-logo.png.ts
export async function GET({ params, request }) {
const response = await fetch(
"https://docs.astro.js.cn/assets/full-logo-light.png",
);
return new Response(await response.arrayBuffer());
}

你也可以使用 APIRoute 类型来为你的端点函数添加类型:

import type { APIRoute } from "astro";
export const GET: APIRoute = async ({ params, request }) => {...}

端点支持与页面相同的动态路由功能。用方括号参数命名你的文件,并导出一个 getStaticPaths() 函数。然后,你可以通过传递给端点函数的 params 属性来访问该参数:

src/pages/api/[id].json.ts
import type { APIRoute } from "astro";
const usernames = ["Sarah", "Chris", "Yan", "Elian"];
export const GET: APIRoute = ({ params, request }) => {
const id = params.id;
return new Response(
JSON.stringify({
name: usernames[id],
}),
);
};
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。端点的动态路由与页面的工作方式相同,但由于端点是一个函数而不是一个组件,因此不支持 props

所有端点都会收到一个 request 属性,但在静态模式下,你只能访问 request.url。它返回当前端点的完整 URL,其工作方式与页面的 Astro.request.url 相同。

src/pages/request-path.json.ts
import type { APIRoute } from "astro";
export const GET: APIRoute = ({ params, request }) => {
return new Response(
JSON.stringify({
path: new URL(request.url).pathname,
}),
);
};

静态文件端点部分描述的所有内容也同样适用于 SSR 模式:文件可以导出一个 GET 函数,它接收一个上下文对象,其属性与 Astro 全局对象类似。

但是,与 static 模式不同,当你为某个路由启用按需渲染时,端点将在被请求时构建。这解锁了构建时不可用的新功能,并允许你构建 API 路由,这些路由可以在运行时监听请求并在服务器上安全地执行代码。

server 模式下,你的路由将默认按需渲染。在 static 模式下,你必须为每个自定义端点使用 export const prerender = false 来选择退出预渲染。

服务器端点无需导出 getStaticPaths 即可访问 params,并且它们可以返回一个 Response 对象,允许你设置状态码和请求头:

src/pages/[id].json.js
import { getProduct } from "../db";
export async function GET({ 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",
},
});
}

这将响应任何匹配动态路由的请求。例如,如果我们导航到 /helmet.jsonparams.id 将被设置为 helmet。如果 helmet 存在于模拟的产品数据库中,端点将使用 Response 对象以 JSON 格式响应,并返回一个成功的 HTTP 状态码。如果不存在,它将使用 Response 对象响应一个 404

在 SSR 模式下,某些提供商要求返回图像时需要 Content-Type 标头。在这种情况下,请使用 Response 对象来指定一个 headers 属性。例如,要生成一个二进制的 .png 图像:

src/pages/astro-logo.png.ts
export async function GET({ params, request }) {
const response = await fetch(
"https://docs.astro.js.cn/assets/full-logo-light.png",
);
const buffer = Buffer.from(await response.arrayBuffer());
return new Response(buffer, {
headers: { "Content-Type": "image/png" },
});
}

除了 GET 函数,你还可以导出一个以任何 HTTP 方法命名的函数。当请求进来时,Astro 会检查请求方法并调用相应的函数。

你还可以导出一个 ALL 函数来匹配任何没有相应导出函数的请求方法。如果一个请求没有匹配的方法,它将被重定向到你网站的 404 页面

src/pages/methods.json.ts
export const GET: APIRoute = ({ params, request }) => {
return new Response(
JSON.stringify({
message: "This was a GET!",
}),
);
};
export const POST: APIRoute = ({ request }) => {
return new Response(
JSON.stringify({
message: "This was a POST!",
}),
);
};
export const DELETE: APIRoute = ({ request }) => {
return new Response(
JSON.stringify({
message: "This was a DELETE!",
}),
);
};
export const ALL: APIRoute = ({ request }) => {
return new Response(
JSON.stringify({
message: `This was a ${request.method}!`,
}),
);
};

如果你定义了 GET 函数但没有定义 HEAD 函数,Astro 将通过调用 GET 函数并从响应中剥离正文来自动处理 HEAD 请求。

在 SSR 模式下,request 属性返回一个完整的、可用的 Request 对象,它指向当前的请求。这允许你接收数据和检查请求头:

src/pages/test-post.json.ts
export const POST: APIRoute = 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 });
};

端点上下文导出一个 redirect() 实用工具,类似于 Astro.redirect

src/pages/links/[id].js
import { getLinkUrl } from "../db";
export async function GET({ 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);
}
贡献 社区 赞助