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:
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
:
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/app
标题部分 astro/app该模块用于渲染通过 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:
app.render()
标题部分 app.render()类型:(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);
RenderOptions
标题部分 RenderOptions类型:{addCookieHeader?: boolean; clientAddress?: string; locals?: object; routeData?: RouteData;}
¥Type: {addCookieHeader?: boolean; clientAddress?: string; locals?: object; routeData?: RouteData;}
app.render()
方法接受强制性的 request
参数和可选的 RenderOptions
对象(用于 addCookieHeader
、clientAddress
、locals
和 routeData
)。
¥The app.render()
method accepts a mandatory request
argument, and an optional RenderOptions
object for addCookieHeader
, clientAddress
, locals
, and routeData
.
addCookieHeader
标题部分 addCookieHeader类型: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 });
clientAddress
标题部分 clientAddress类型: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 });
locals
标题部分 locals类型: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
标题部分 routeData类型: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 });}
app.match()
标题部分 app.match()类型:(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 特性
标题部分 Astro 特性¥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:
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:
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.
edgeMiddleware
标题部分 edgeMiddleware类型: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:
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
、URL
。
¥Then, consume the hook astro:build:ssr
, which will give you a middlewareEntryPoint
, an URL
to the physical file on the file system.
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}
envGetSecret
标题部分 envGetSecret类型: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:
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 } };}
buildOutput
标题部分 buildOutput类型:'static' | 'server'
¥Type: 'static' | 'server'
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.
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' } }); }, }, };}