构建输出配置
构建输出配置是一个基于文件系统的规范,用于定义框架的构建产物。它提供了一种标准化方式,使框架适配器能够以统一格式输出构建结果,并部署到 EdgeOne Pages 平台。
概述
构建输出 API 与 EdgeOne Pages 产品功能以逻辑清晰、易于理解的方式紧密对应。如果您是希望与 EdgeOne Pages 集成的框架作者,您可以使用此参考资料来了解框架应该向
.edgeone目录输出哪些文件。您可以自行创建
.edgeone目录并根据此规范填充它。下文中我们将提供详细说明,以便开发者了解如何使用构建输出您自己的框架适配器。整体目录结构
开发者需要关注的核心在于
.edgeone/cloud-functions/ssr-node/config.json,config.json 文件包含部署的配置信息。对于 Web 全栈框架服务端入口文件应命名为
handler.js。config.json 支持字段
version
version 属性表示实现的 Build Output API 版本。本文档描述的版本为 3。{"version": 3}
routes
routes 属性描述将应用于部署的路由规则。路由可用于将某些 URL 路径指向部署中的其他路径、为路径附加响应头、实现重定向以及各种其他路由相关的用例。type Route = Source | Handler;
Source 路由
type Source = {src: string;dest?: string;headers?: Record<string, string>;methods?: string[];continue?: boolean;status?: number;has?: HasField[];missing?: HasField[];};
字段 | 类型 | 必需 | 描述 |
src | String | 是 | 一个与 RE2 兼容的正则表达式,用于匹配每个传入的路径名(不包括 query string)。 |
dest | String | 否 | 重写目标路径或完整 URL(包括 querystring),支持捕获组 $1、$2。如果不提供,则直接使用客户端请求的原始路径回源。 |
headers | Record <string, string> | 否 | 应用于响应的一组 HTTP 响应头。 |
methods | String[] | 否 | 一组 HTTP 方法类型。如果未提供,则任何 HTTP 方法的请求都将成为路由的候选。 |
continue | Boolean | 否 | 用于更改匹配行为的布尔值。如果为 true,即使 src 匹配,路由仍将继续匹配后续规则。 |
status | Number | 否 | 响应的状态码。必须配合 headers.Location 使用才能实现重定向,Location 支持捕获组 $1、$2 等。 |
has | HasField[] | 否 | 应用路由时必须满足的 HTTP 请求条件(header/cookie/query/host)。 |
missing | HasField[] | 否 | 应用路由时必须不满足的 HTTP 请求条件(反向条件匹配)。 |
Source 路由:HasField
type HasField = Array<{ type: 'host', value: string }{type: 'header' | 'cookie' | 'query';key: string;value?: string;}>;
字段 | 类型 | 必需 | 描述 |
type | "host" | "header" | "cookie" | "query" | 是 | 确定 HasField 类型。 |
key | String | 否 | header、cookie 和 query 类型时必需。要匹配的键名。 |
value | String | 否 | 要匹配的值(支持正则)。 |
Handler 路由
路由系统使用
handle 值标识路由阶段的分界点。EdgeOne 仅支持 handle: "filesystem"。type Handler = {handle: 'filesystem';};
字段 | 类型 | 必需 | 描述 |
handle | "filesystem" | 是 | 静态文件查找的分界标记。仅支持 "filesystem"。 |
{"version": 3,"routes": [// 阶段一:预处理阶段(filesystem 之前)// 用于:重定向、设置响应头等{ "src": "^/_next/static/(.*)$", "headers": { "cache-control": "public, max-age=31536000, immutable" } },{ "handle": "filesystem" },// 阶段二:回源阶段(filesystem 之后)// 用于:API 路由、SSR 页面、函数调用{ "src": "^/api/(.*)$", "dest": "/api/$1" },{ "src": "/.*" }]}
说明:
handle: "filesystem" 前后的路由配置格式完全相同,无需特殊处理。输出位置
根据 Builder 类型,将对应文件写入不同目录, Web 全栈的框架固定放置在
cloud-functions/ssr-node 中Builder 类型 | 输出位置 |
静态资源 | assets/ |
Node.js SSR 函数 | cloud-functions/ssr-node/ |
Node.js API 函数 | cloud-functions/api-node/ |
Go API 函数 | cloud-functions/api-go/ |
Python API 函数 | cloud-functions/api-python/ |
Edge 函数 | edge-functions/ |
Node.js API
源码目录结构:
cloud-functions/├── api/│ ├── users.js│ └── posts/[id].js└── hello.js
构建输出目录结构:
cloud-functions/├── api-node/│ ├── node_modules/│ ├── index.mjs│ └── config.json...
生成的
config.json:{"version": 3,"routes": [{ "src": "^/api/users$", "dest": "/api/users" },{ "src": "^/api/posts/([^/]+)$", "dest": "/api/posts/$1" },{"src": "^/hello-node$","methods": ["GET","POST","PUT","DELETE","PATCH","HEAD","OPTIONS"]}]}
Go API
Handler 模式
源码目录结构:
cloud-functions/├── api/│ ├── users.go│ └── posts/[id].go├── health.go├── go.mod└── go.sum
构建输出目录结构:
cloud-functions/api-go├── config.json├── go.mod└── main.go // handler 模式下输出产物入口文件文件名固定为 main
生成的
config.json:{"version": 3,"routes": [{"src": "^/api/users/?$"},{"src": "^/health/?$"},{"src": "^/api/posts/([^/]+)/?$"}]}
Framework 模式
源码目录结构:
cloud-functions/├── api.go├── go.mod└── go.sum
构建输出目录结构:
cloud-functions/api-go├── config.json├── go.mod└── api.go //该文件名与源码入口文件的文件名相同
生成的
config.json:{"version": 3,"framework": "gin","routes": [{"src": "^/api(.*)$"}]}
Python API
Handler 模式
源码目录结构:
cloud-functions/├── api/│ └── users.py├── hello.py└── requirements.txt (可选)
构建输出目录结构:
cloud-functions/api-python├── config.json├── app.py // 入口文件,固定为 app.py├── requirements.txt├── api/│ └── users.py├── hello.py└── <dependencies>/ // 第三方依赖包(安装到产物目录下)
生成的
config.json:{"vsersion": 3,"routes": [{"src": "^/api/users$"},{"src": "^/hello$"}]}
Framework 模式
源码目录结构(以 FastAPI 为例):
cloud-functions/├── demo-fastapi.py└── requirements.txt (可选)
构建输出目录结构:
cloud-functions/api-python├── config.json├── app.py // 入口文件,固定为 app.py├── requirements.txt├── demo-fastapi.py└── <dependencies>/ // 第三方依赖包(如 fastapi、uvicorn 等)
生成的
config.json:{"version": 3,"routes": [{"src": "^/demo-fastapi$"}]}
常见场景
URL 重定向
// 固定路径重定向{ "src": "^/old-path$", "headers": { "Location": "/new-path" }, "status": 301 }// 动态路径重定向(支持捕获组){ "src": "^/blog/(.*)$", "headers": { "Location": "/posts/$1" }, "status": 301 }// 完整 URL 重定向{ "src": "^/external$", "headers": { "Location": "https://example.com/page" }, "status": 302 }
说明:
重定向使用
headers.Location + status 组合Location 可以是相对路径(如 /new-path)或完整 URLLocation 中可以使用 $1、$2 等捕获组变量,实现动态重定向Catch-all
将所有请求重写到根路径 index.html,通常用于单页应用程序(SPA)。
{"src": "/.*","dest": "index.html"}
设置响应头
{"src": "^/_next/static/(.*)$","headers": { "cache-control": "public, max-age=31536000, immutable" }}
Clean URLs
{ "src": "^/about$", "dest": "/about.html" }
动态路由
{ "src": "^/blog/([^/]+)$", "dest": "/blog/$1" }
说明:使用正则捕获组 $1 来传递动态参数
完整示例
{"version": 3,"routes": [{"src": "^/([^.]+[^/.])$","dest": "/$1/","continue": true},{"src": "/test-ssg","headers": {"Cache-Control": "max-age=3600"}},{"src": "/api/cookies-test","headers": {"Cache-Control": "public, max-age=60, stale-while-revalidate=300"}},{"handle": "filesystem"},{"src": "^/about$","dest": "/about.html"},{"src": "^/blog/([^/]+)$","dest": "/blog/$1"},{"src": "^/api/cookies-test-cache$"},{"src": "^/api/seconde/query-test$"},{"src": "^/api/cookies-test$"},{"src": "^/posts/([^/]+)$"},{"src": "^/auth$"},{"src": "^/$"},{"src": "^/(.*)$"}]}
目前局限
