Skip to content

Astro 适配器 API

Astro 旨在轻松部署到任何云提供商以进行按需渲染,也称为服务器端渲染 (SSR)。这种能力是由 integrations 适配器提供的。请参阅 按需渲染指南 了解如何使用现有适配器。

¥Astro is designed to make it easy to deploy to any cloud provider for on-demand rendering, also known as server-side rendering (SSR). This ability is provided by adapters, which are integrations. See the on-demand rendering guide to learn how to use an existing adapter.

¥What is an adapter?

适配器是一种特殊的 integration,它在请求时提供服务器渲染的入口点。适配器有两件事:

¥An adapter is a special kind of integration that provides an entrypoint for server rendering at request time. An adapter does two things:

  • 实现特定于主机的 API 来处理请求。

  • 根据主机约定配置构建。

¥Building an Adapter

适配器是 integration,可以执行集成可以执行的任何操作。

¥An adapter is an integration and can do anything that an integration can do.

适配器必须在 astro:config:done 钩子中调用 setAdapter API,如下所示:

¥An adapter must call the setAdapter API in the astro:config:done hook like so:

my-adapter.mjs
export default function createIntegration() {
return {
name: '@matthewp/my-adapter',
hooks: {
'astro:config:done': ({ setAdapter }) => {
setAdapter({
name: '@matthewp/my-adapter',
serverEntrypoint: '@matthewp/my-adapter/server.js',
supportedAstroFeatures: {
staticOutput: 'stable'
}
});
},
},
};
}

传入 setAdapter 的对象定义为:

¥The object passed into setAdapter is defined as:

interface AstroAdapter {
name: string;
serverEntrypoint?: string;
previewEntrypoint?: string;
exports?: string[];
args?: any;
adapterFeatures?: AstroAdapterFeatures;
supportedAstroFeatures: AstroAdapterFeatureMap;
}
export interface AstroAdapterFeatures {
/**
* Creates an edge function that will communicate with the Astro middleware.
*/
edgeMiddleware: boolean;
/**
* Determine the type of build output the adapter is intended for. Defaults to `server`;
*/
buildOutput?: 'static' | 'server';
}
export type AdapterSupportsKind = 'unsupported' | 'stable' | 'experimental' | 'deprecated' | 'limited';
export type AdapterSupportWithMessage = {
support: Exclude<AdapterSupportsKind, 'stable'>;
message: string;
};
export type AdapterSupport = AdapterSupportsKind | AdapterSupportWithMessage;
export type AstroAdapterFeatureMap = {
/**
* The adapter is able to serve static pages
*/
staticOutput?: AdapterSupport;
/**
* The adapter is able to serve pages that are static or rendered via server
*/
hybridOutput?: AdapterSupport;
/**
* The adapter is able to serve pages rendered on demand
*/
serverOutput?: AdapterSupport;
/**
* The adapter is able to support i18n domains
*/
i18nDomains?: AdapterSupport;
/**
* The adapter is able to support `getSecret` exported from `astro:env/server`
*/
envGetSecret?: AdapterSupport;
/**
* The adapter supports the Sharp image service
*/
sharpImageService?: AdapterSupport;
};

属性是:

¥The properties are:

  • 名称:适配器的唯一名称,用于日志记录。

  • serverEntrypoint:按需服务器渲染的入口点。

  • 导出:与 createExports 结合使用时的命名导出数组(如下所述)。

  • adapterFeatures:启用适配器必须支持的特定功能的对象。这些功能将改变构建的输出,适配器必须实现正确的逻辑来处理不同的输出。

  • supportedAstroFeatures:Astro 内置功能图。这使得 Astro 能够确定适配器无法或不愿意支持哪些功能,从而可以提供适当的错误消息。

¥Server Entrypoint

Astro 的适配器 API 尝试与任何类型的主机一起工作,并提供了一种灵活的方式来符合主机 API。

¥Astro’s adapter API attempts to work with any type of host, and gives a flexible way to conform to the host APIs.

¥Exports

一些无服务器主机希望你导出函数,例如 handler

¥Some serverless hosts expect you to export a function, such as handler:

export function handler(event, context) {
// ...
}

使用适配器 API,你可以通过在 serverEntrypoint 中实现 createExports 来实现此目的:

¥With the adapter API you achieve this by implementing createExports in your serverEntrypoint:

import { App } from 'astro/app';
export function createExports(manifest) {
const app = new App(manifest);
const handler = (event, context) => {
// ...
};
return { handler };
}

然后在你调用 setAdapter 的集成中,在 exports 中提供此名称:

¥And then in your integration, where you call setAdapter, provide this name in exports:

my-adapter.mjs
export default function createIntegration() {
return {
name: '@matthewp/my-adapter',
hooks: {
'astro:config:done': ({ setAdapter }) => {
setAdapter({
name: '@matthewp/my-adapter',
serverEntrypoint: '@matthewp/my-adapter/server.js',
exports: ['handler'],
});
},
},
};
}

¥Start

有些主机希望你自己启动服务器,例如通过监听端口。对于这些类型的主机,适配器 API 允许你导出 start 函数,该函数将在运行打包脚本时调用。

¥Some hosts expect you to start the server yourselves, for example by listening to a port. For these types of hosts, the adapter API allows you to export a start function which will be called when the bundle script is run.

import { App } from 'astro/app';
export function start(manifest) {
const app = new App(manifest);
addEventListener('fetch', event => {
// ...
});
}

该模块用于渲染通过 astro build.0 预构建的页面。Astro 使用标准 要求响应 对象。具有不同请求/响应 API 的主机应在其适配器中转换为这些类型。

¥This module is used for rendering pages that have been prebuilt through astro build. Astro uses the standard Request and Response objects. Hosts that have a different API for request/response should convert to these types in their adapter.

import { App } from 'astro/app';
import http from 'http';
export function start(manifest) {
const app = new App(manifest);
addEventListener('fetch', event => {
event.respondWith(
app.render(event.request)
);
});
}

提供以下方法:

¥The following methods are provided:

类型:(request: Request, options?: RenderOptions) => Promise<Response>

¥Type: (request: Request, options?: RenderOptions) => Promise<Response>

该方法调用与请求匹配的 Astro 页面,渲染它,并向 响应 对象返回 Promise。这也适用于不渲染页面的 API 路由。

¥This method calls the Astro page that matches the request, renders it, and returns a Promise to a Response object. This also works for API routes that do not render pages.

const response = await app.render(request);

类型:{addCookieHeader?: boolean; clientAddress?: string; locals?: object; routeData?: RouteData;}

¥Type: {addCookieHeader?: boolean; clientAddress?: string; locals?: object; routeData?: RouteData;}

app.render() 方法接受强制性的 request 参数和可选的 RenderOptions 对象(用于 addCookieHeaderclientAddresslocalsrouteData)。

¥The app.render() method accepts a mandatory request argument, and an optional RenderOptions object for addCookieHeader, clientAddress, locals, and routeData.

类型:boolean
默认:false

¥Type: boolean
Default: false

是否自动将 Astro.cookie.set() 编写的所有 cookie 添加到响应标头。

¥Whether or not to automatically add all cookies written by Astro.cookie.set() to the response headers.

设置为 true 时,它们将作为逗号分隔的键值对添加到响应的 Set-Cookie 标头中。你可以使用标准 response.headers.getSetCookie() API 单独读取它们。设置为 false(默认)时,cookie 只能从 App.getSetCookieFromResponse(response) 获得。

¥When set to true, they will be added to the Set-Cookie header of the response as comma separated key-value pairs. You can use the standard response.headers.getSetCookie() API to read them individually. When set to false(default), the cookies will only be available from App.getSetCookieFromResponse(response).

const response = await app.render(request, { addCookieHeader: true });

类型:string
默认:request[Symbol.for("astro.clientAddress")]

¥Type: string
Default: request[Symbol.for("astro.clientAddress")]

客户端 IP 地址将在页面中作为 Astro.clientAddress 提供,在 API 路由和中间件中作为 ctx.clientAddress 提供。

¥The client IP address that will be made available as Astro.clientAddress in pages, and as ctx.clientAddress in API routes and middleware.

以下示例读取 x-forwarded-for 标头并将其作为 clientAddress 传递。此值作为 Astro.clientAddress 提供给用户。

¥The example below reads the x-forwarded-for header and passes it as clientAddress. This value becomes available to the user as Astro.clientAddress.

const clientAddress = request.headers.get("x-forwarded-for");
const response = await app.render(request, { clientAddress });

类型:object

¥Type: object

context.locals object 用于在请求的生命周期内存储和访问信息。

¥The context.locals object used to store and access information during the lifecycle of a request.

下面的示例读取名为 x-private-header 的标头,尝试将其解析为对象并将其传递给 locals,然后可以将其传递给任何 中间件函数

¥The example below reads a header named x-private-header, attempts to parse it as an object and pass it to locals, which can then be passed to any middleware function.

const privateHeader = request.headers.get("x-private-header");
let locals = {};
try {
if (privateHeader) {
locals = JSON.parse(privateHeader);
}
} finally {
const response = await app.render(request, { locals });
}

类型:RouteData
默认:app.match(request)

¥Type: RouteData
Default: app.match(request)

如果你已经知道渲染路径,请提供 integrationRouteData 的值。这样做将绕过对 app.match 的内部调用来确定渲染路由。

¥Provide a value for integrationRouteData if you already know the route to render. Doing so will bypass the internal call to app.match to determine the route to render.

const routeData = app.match(request);
if (routeData) {
return app.render(request, { routeData });
} else {
/* adapter-specific 404 response */
return new Response(..., { status: 404 });
}

类型:(request: Request) => RouteData | undefined

¥Type: (request: Request) => RouteData | undefined

此方法用于确定请求是否符合 Astro 应用的路由规则。

¥This method is used to determine if a request is matched by the Astro app’s routing rules.

if(app.match(request)) {
const response = await app.render(request);
}

你通常可以在不使用 .match 的情况下调用 app.render(request),因为如果你提供 404.astro 文件,Astro 会处理 404。如果你想以不同的方式处理 404,请使用 app.match(request)

¥You can usually call app.render(request) without using .match because Astro handles 404s if you provide a 404.astro file. Use app.match(request) if you want to handle 404s in a different way.

允许通过 astro add 安装

标题部分 允许通过 astro add 安装

¥Allow installation via astro add

astro add 命令 允许用户轻松地将集成和适配器添加到他们的项目中。如果你希望你的适配器可以使用此工具安装,请将 astro-adapter 添加到 package.json 中的 keywords 字段:

¥The astro add command allows users to easily add integrations and adapters to their project. If you want your adapter to be installable with this tool, add astro-adapter to the keywords field in your package.json:

{
"name": "example",
"keywords": ["astro-adapter"],
}

完成 将你的适配器发布到 npm 后,运行 astro add example 将安装你的软件包以及 package.json 中指定的任何对等依赖。我们还将指导用户手动更新他们的项目配置。

¥Once you publish your adapter to npm, running astro add example will install your package with any peer dependencies specified in your package.json. We will also instruct users to update their project config manually.

¥Astro features

Added in: astro@3.0.0

Astro 功能是适配器告诉 Astro 是否能够支持某个功能以及适配器的支持级别的一种方式。

¥Astro features are a way for an adapter to tell Astro whether they are able to support a feature, and also the adapter’s level of support.

当使用这些属性时,Astro 将:

¥When using these properties, Astro will:

  • 运行特定验证;

  • 向日志发出上下文;

这些操作根据支持或不支持的功能、其支持级别以及用户使用的配置来运行。

¥These operations are run based on the features supported or not supported, their level of support, and the configuration that the user uses.

以下配置告诉 Astro,此适配器对 Sharp 内置图片服务具有实验性支持:

¥The following configuration tells Astro that this adapter has experimental support for the Sharp-powered built-in image service:

my-adapter.mjs
export default function createIntegration() {
return {
name: '@matthewp/my-adapter',
hooks: {
'astro:config:done': ({ setAdapter }) => {
setAdapter({
name: '@matthewp/my-adapter',
serverEntrypoint: '@matthewp/my-adapter/server.js',
supportedAstroFeatures: {
sharpImageService: 'experimental'
}
});
},
},
};
}

如果使用 Sharp 图片服务,Astro 将根据你的适配器支持向终端记录警告和错误:

¥If the Sharp image service is used, Astro will log a warning and error to the terminal based on your adapter’s support:

[@matthewp/my-adapter] The feature is experimental and subject to issues or changes.
[@matthewp/my-adapter] The currently selected adapter `@matthewp/my-adapter` is not compatible with the service "Sharp". Your project will NOT be able to build.

可以另外提供一条消息,为用户提供更多上下文:

¥A message can additionally be provided to give more context to the user:

my-adapter.mjs
export default function createIntegration() {
return {
name: '@matthewp/my-adapter',
hooks: {
'astro:config:done': ({ setAdapter }) => {
setAdapter({
name: '@matthewp/my-adapter',
serverEntrypoint: '@matthewp/my-adapter/server.js',
supportedAstroFeatures: {
sharpImageService: {
support: 'limited',
message: 'This adapter has limited support for Sharp, certain features may not work as expected.'
}
}
});
},
},
};
}

¥Adapter features

一组更改发出文件的输出的功能。当适配器选择使用这些功能时,他们将在特定的钩子中获得附加信息。

¥A set of features that changes the output of the emitted files. When an adapter opts in to these features, they will get additional information inside specific hooks.

类型:boolean

¥Type: boolean

定义在构建时是否会打包任何按需渲染中间件代码。

¥Defines whether any on-demand rendering middleware code will be bundled when built.

启用后,这可以防止中间件代码在构建期间被所有页面打包和导入:

¥When enabled, this prevents middleware code from being bundled and imported by all pages during the build:

my-adapter.mjs
export default function createIntegration() {
return {
name: '@matthewp/my-adapter',
hooks: {
'astro:config:done': ({ setAdapter }) => {
setAdapter({
name: '@matthewp/my-adapter',
serverEntrypoint: '@matthewp/my-adapter/server.js',
adapterFeatures: {
edgeMiddleware: true
}
});
},
},
};
}

然后,使用钩子 astro:build:ssr,这将为你提供文件系统上物理文件的 middlewareEntryPointURL

¥Then, consume the hook astro:build:ssr, which will give you a middlewareEntryPoint, an URL to the physical file on the file system.

my-adapter.mjs
export default function createIntegration() {
return {
name: '@matthewp/my-adapter',
hooks: {
'astro:config:done': ({ setAdapter }) => {
setAdapter({
name: '@matthewp/my-adapter',
serverEntrypoint: '@matthewp/my-adapter/server.js',
adapterFeatures: {
edgeMiddleware: true
}
});
},
'astro:build:ssr': ({ middlewareEntryPoint }) => {
// remember to check if this property exits, it will be `undefined` if the adapter doesn't opt in to the feature
if (middlewareEntryPoint) {
createEdgeMiddleware(middlewareEntryPoint)
}
}
},
};
}
function createEdgeMiddleware(middlewareEntryPoint) {
// emit a new physical file using your bundler
}

类型:AdapterSupportsKind

¥Type: AdapterSupportsKind

此功能允许你的适配器检索用户在 env.schema 中配置的机密。

¥This is a feature to allow your adapter to retrieve secrets configured by users in env.schema.

通过将任何有效的 AdapterSupportsKind 值传递给适配器来启用该功能:

¥Enable the feature by passing any valid AdapterSupportsKind value to the adapter:

my-adapter.mjs
export default function createIntegration() {
return {
name: '@matthewp/my-adapter',
hooks: {
'astro:config:done': ({ setAdapter }) => {
setAdapter({
name: '@matthewp/my-adapter',
serverEntrypoint: '@matthewp/my-adapter/server.js',
adapterFeatures: {
envGetSecret: 'stable'
}
});
},
},
};
}

astro/env/setup 模块允许你为 getSecret() 提供实现。在你的服务器入口点,尽快调用 setGetEnv()

¥The astro/env/setup module allows you to provide an implementation for getSecret(). In your server entrypoint, call setGetEnv() as soon as possible:

import { App } from 'astro/app';
import { setGetEnv } from "astro/env/setup"
setGetEnv((key) => process.env[key])
export function createExports(manifest) {
const app = new App(manifest);
const handler = (event, context) => {
// ...
};
return { handler };
}

如果你支持机密,请确保在环境变量与请求绑定时在 getSecret() 之前调用 setGetEnv()

¥If you support secrets, be sure to call setGetEnv() before getSecret() when your environment variables are tied to the request:

import type { SSRManifest } from 'astro';
import { App } from 'astro/app';
import { setGetEnv } from 'astro/env/setup';
import { createGetEnv } from '../utils/env.js';
type Env = {
[key: string]: unknown;
};
export function createExports(manifest: SSRManifest) {
const app = new App(manifest);
const fetch = async (request: Request, env: Env) => {
setGetEnv(createGetEnv(env));
const response = await app.render(request);
return response;
};
return { default: { fetch } };
}

类型:'static' | 'server'

¥Type: 'static' | 'server'

Added in: astro@5.0.0

此属性允许你强制构建特定的输出形状。这对于仅适用于特定输出类型的适配器很有用,例如,你的适配器可能需要静态网站,但使用适配器创建特定于主机的文件。如果未指定,则默认为 server

¥This property allows you to force a specific output shape for the build. This can be useful for adapters that only work with a specific output type, for instance, your adapter might expect a static website, but uses an adapter to create host-specific files. Defaults to server if not specified.

my-adapter.mjs
export default function createIntegration() {
return {
name: '@matthewp/my-adapter',
hooks: {
'astro:config:done': ({ setAdapter }) => {
setAdapter({
name: '@matthewp/my-adapter',
serverEntrypoint: '@matthewp/my-adapter/server.js',
adapterFeatures: {
buildOutput: 'static'
}
});
},
},
};
}
Astro 中文网 - 粤ICP备13048890号