Skip to main content
On this page

从 subhosting API v1 迁移到 v2

本指南介绍如何将 Deno Deploy subhosting API v1 (api.deno.com/v1) 迁移到 v2 (api.deno.com/v2)。v1 API 将于 2026 年 7 月 20 日 关闭。有关通用平台迁移(应用、域名、环境变量),请参阅 Deploy Classic 迁移指南

完整的 v2 API 参考文档:api.deno.com/v2/docs

官方 SDK:

这些 SDK 的品牌名是 "sandbox",但可用于 subhosting 场景。

为什么要迁移到 v2 Jump to heading

v2 运行在一个完全不同的新平台上,并带来了显著改进:

  • 不再有每个请求的 CPU 时间限制(不再出现 TIME_LIMIT 错误)
  • 可配置的内存限制,最高 4 GB(v1 固定为 512 MB)
  • 可将自定义 OpenTelemetry 导出(日志、指标、追踪)发送到你自己的端点
  • 自定义构建步骤和框架支持(Next.js、Astro、SvelteKit 等)
  • 内置 HTTP 缓存
  • 通过 layers 在不重新部署的情况下,跨多个应用即时批量更新配置
  • Web 应用防火墙(WAF)

关键概念变化 Jump to heading

v1 v2 备注
Organization Organization 无变化
Project App 一个函数对应一个 app
Deployment Revision 代码 + 配置的不可变快照
Project name App slug 用于 URL;在组织内唯一
Labels 用于分组/筛选 app 的键值对
Layers 跨 app 共享的配置(环境变量)
Config 构建和运行时配置
Timeline app 内的部署目标

架构变化:一个函数对应一个 app Jump to heading

在 v1 中,你可能使用一个包含多个活动部署的项目来表示不同的函数。在 v2 中,请为每个函数创建一个单独的 app。

v2 引入了 timelines。每个 timeline 在任意时刻只有一个活动 revision——部署新的 revision 会替换之前的 revision。通过 API 部署时,revision 会自动标记为 production,因此每个 app 实际上只有一个活动 revision。

这意味着 v2 的 revisions 并不与 v1 的 deployments 一一对应。在 v1 中,同一个项目内可以同时存在多个活动部署。在 v2 中,每个 timeline 只有一个活动 revision。

推荐做法:

  • 为每个函数创建一个 app,并使用具有描述性的 slug(例如 my-service-authmy-service-billing
  • 使用 labels 对相关 app 分组——可通过 GET /apps?labels[service]=my-service 过滤
  • 使用 layers 在多个 app 之间共享环境变量

配置继承 Jump to heading

在 v1 中,每个部署都是自包含的:环境变量、入口点以及其他选项都必须在每次 deploy 请求中指定。

在 v2 中,app 会携带配置,并由 revision 继承:

  • 构建配置 (config):安装命令、构建命令、运行时入口点。只需在 app 上设置一次,所有 revision 都会继承。
  • 环境变量 (env_vars):可在 app 或 layer 上设置,所有 revision 都会继承。
  • Layers:设置在 app 上,所有 revision 都会继承。

你可以通过在 deploy 请求中包含这些字段,按 revision 进行覆盖。若省略,则使用 app 的配置。这意味着在初始设置后,通常只需要发送 assets

{
  "assets": {
    "main.ts": {
      "kind": "file",
      "content": "Deno.serve((req) => new Response('Hello'));"
    }
  }
}

身份验证 Jump to heading

Aspect v1 v2
Token prefix dd... ddo_...
Header Authorization: Bearer <token> Authorization: Bearer <token>
Scope Organization Organization
Base URL https://api.deno.com/v1 https://api.deno.com/v2

请在 Deno Deploy 控制台的组织设置中创建 v2 token。

端点映射 Jump to heading

列出 projects / apps Jump to heading

v1: GET /organizations/{orgId}/projects

v2: GET /apps

v2 API 会根据你的 token 自动作用于对应的组织。URL 中不需要组织 ID。

>_
# v1
curl -H "Authorization: Bearer $TOKEN" \
  "https://api.deno.com/v1/organizations/$ORG_ID/projects?page=1&limit=20"

# v2
curl -H "Authorization: Bearer $TOKEN" \
  "https://api.deno.com/v2/apps?limit=30"
Aspect v1 v2
Pagination page + limit(基于页码) cursor + limit(基于游标)
Filtering q(按名称/ID 搜索) labelslayer
Response Project 对象数组 AppListItem 对象数组

响应字段映射:

v1 Project v2 AppListItem
id (UUID) id (UUID)
name slug
description 不可用
createdAt created_at
updatedAt updated_at
labels(对象)
layers{id, slug} 数组)

v2 对所有字段名使用 snake_case(v1 使用 camelCase)。

获取 project / app 详情 Jump to heading

v1: GET /projects/{projectId}

v2: GET /apps/{app}

v2 端点接受 app 的 UUID 或 slug。

>_
# v1
curl -H "Authorization: Bearer $TOKEN" \
  "https://api.deno.com/v1/projects/$PROJECT_ID"

# v2
curl -H "Authorization: Bearer $TOKEN" \
  "https://api.deno.com/v2/apps/my-app-slug"

v2 响应包含 env_varsconfiglabelslayers

创建 deployment / revision Jump to heading

v1: POST /projects/{projectId}/deployments

v2: POST /apps/{app}/deploy

这是最重要的 API 变更。

v1 请求 Jump to heading

{
  "entryPointUrl": "main.ts",
  "assets": {
    "main.ts": {
      "content": "Deno.serve((req) => new Response('Hello'));",
      "encoding": "utf-8"
    }
  },
  "envVars": {
    "MY_VAR": "my_value"
  }
}

v2 请求 Jump to heading

{
  "assets": {
    "main.ts": {
      "kind": "file",
      "content": "Deno.serve((req) => new Response('Hello'));",
      "encoding": "utf-8"
    }
  },
  "config": {
    "install": "deno install",
    "runtime": {
      "type": "dynamic",
      "entrypoint": "main.ts"
    }
  },
  "env_vars": [
    { "key": "MY_VAR", "value": "my_value" }
  ]
}

主要差异:

Aspect v1 v2
Entrypoint 顶层 entryPointUrl config.runtime.entrypoint
Assets content+encodinggitSha1 kind: "file" 搭配 content+encoding,或 kind: "symlink" 搭配 target
Env vars 对象 {"KEY": "value"} 数组 [{"key": "KEY", "value": "value"}]
Import map importMapUrl 字段 不需要;Deno 会自动发现 deno.json
Lock file lockFileUrl 字段 不需要;由 deno install 处理
Compiler options compilerOptions 字段 不需要;使用 deno.json
Build config 无(仅导入缓存) config.installconfig.build
Response status 200 202 Accepted(构建是异步的)
Databases/KV databases 字段 不可用
Request timeout requestTimeout 字段 不可用
Permissions permissions 字段 不可用

构建配置: 在 v1 中,"build" 步骤仅用于缓存导入。在 v2 中,对应的是 config.install: "deno install" 搭配 config.build: null。 不需要框架预设(将 config.framework 保持为 "")。

配置继承: configenv_varslayers 在 deploy 请求中都是可选的。若省略,revision 将继承 app 的配置。请在创建 app 时一次性设置这些内容,之后的部署只需发送 assets

状态值 Jump to heading

v1 v2 含义
pending queued 构建尚未开始
(none) building 构建中
success succeeded 已部署并生效
failed failed 构建失败
(none) skipped 构建已跳过

获取 deployment / revision 状态 Jump to heading

v1: GET /deployments/{deploymentId}

v2: GET /revisions/{revisionId}

>_
# v1
curl -H "Authorization: Bearer $TOKEN" \
  "https://api.deno.com/v1/deployments/$DEPLOYMENT_ID"

# v2
curl -H "Authorization: Bearer $TOKEN" \
  "https://api.deno.com/v2/revisions/$REVISION_ID"

当状态为 failed 时,v2 响应会包含 failure_reason

列出 deployments / revisions Jump to heading

v1: GET /projects/{projectId}/deployments

v2: GET /apps/{app}/revisions

>_
# v1
curl -H "Authorization: Bearer $TOKEN" \
  "https://api.deno.com/v1/projects/$PROJECT_ID/deployments?page=1&limit=20"

# v2
curl -H "Authorization: Bearer $TOKEN" \
  "https://api.deno.com/v2/apps/my-app-slug/revisions?limit=30"
Aspect v1 v2
Pagination page + limit cursor + limit
Filtering q(按 ID 搜索) status

追踪构建日志 Jump to heading

v1: GET /deployments/{deploymentId}/build_logs(轮询)

v2 提供两种方式:

流式获取 revision 进度(推荐) Jump to heading

GET /revisions/{revisionId}/progress

在构建进展时发出事件。会在 revision 到达终止状态(succeededfailedskipped)时结束。替代了 v1 中循环轮询 deployment 状态的模式。

>_
curl -H "Authorization: Bearer $TOKEN" \
  -H "Accept: text/event-stream" \
  "https://api.deno.com/v2/revisions/$REVISION_ID/progress"

流式获取构建日志 Jump to heading

GET /revisions/{revisionId}/build_logs

>_
curl -H "Authorization: Bearer $TOKEN" \
  -H "Accept: text/event-stream" \
  "https://api.deno.com/v2/revisions/$REVISION_ID/build_logs"
Aspect v1 v2
Formats application/x-ndjsonapplication/json text/event-stream(SSE)、application/x-ndjson
Log fields levelmessage timestamplevelmessagesteptimeline
Filter by step 不支持 step 参数(preparing/installing/building/deploying)

查询 app 日志 Jump to heading

v1: GET /deployments/{deploymentId}/app_logs

v2: GET /apps/{app}/logs

在 v1 中,日志仅限于单个 deployment。v2 中,日志作用于整个 app,并可选按 revision_id 过滤。

>_
# v1
curl -H "Authorization: Bearer $TOKEN" \
  "https://api.deno.com/v1/deployments/$DEPLOYMENT_ID/app_logs?since=2024-01-01T00:00:00Z&until=2024-01-01T01:00:00Z"

# v2
curl -H "Authorization: Bearer $TOKEN" \
  "https://api.deno.com/v2/apps/my-app-slug/logs?start=2024-01-01T00:00:00Z&end=2024-01-01T01:00:00Z"

参数映射:

v1 v2 备注
since start v2 中必需
until end 可选
limit limit v1:最大 10000。v2:最大 1000
order (none) v2 返回按时间顺序的结果
q query 文本搜索
level level v1:warning。v2:warn
region (none) v2 不支持按区域过滤

响应字段映射:

v1 field v2 field
time timestamp
level level
message message
region region
revision_id
trace_id
span_id

v2 会将日志封装在一个带有 next_cursor 的对象中,以便分页:

{
  "logs": [
    {
      "timestamp": "2024-01-01T00:00:01Z",
      "level": "info",
      "message": "Listening on http://0.0.0.0:8000",
      "region": "us-east-1",
      "revision_id": "abcdef12"
    }
  ],
  "next_cursor": "eyJsYXN0X3RzIjoiMjAy..."
}

流式传输: 在 v1 中,省略 sinceuntil 可启用实时流式传输。 在 v2 中,省略 end 参数即可流式传输。将 Accept 头设置为 text/event-stream 可使用 SSE 格式,或设置为 application/x-ndjson 可使用 NDJSON。 如果在没有 end 的情况下请求 application/json,将返回错误。

使用标签对应用分组 Jump to heading

标签取代了 v1 中将多个部署归组到单个 项目下的模式:

>_
# 使用标签创建应用
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  "https://api.deno.com/v2/apps" \
  -d '{
    "slug": "my-service-auth",
    "labels": {
      "service": "my-service",
      "function": "auth"
    },
    "config": {
      "install": "deno install",
      "runtime": {
        "type": "dynamic",
        "entrypoint": "main.ts"
      }
    }
  }'

# 列出某个服务中的所有应用
curl -H "Authorization: Bearer $TOKEN" \
  "https://api.deno.com/v2/apps?labels[service]=my-service"

使用层进行共享配置 Jump to heading

层允许你在多个应用之间共享环境变量。这在 v1 中是不可能的, 因为环境变量必须在每次部署请求中重复传入。

>_
# 创建一个包含共享环境变量的层
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  "https://api.deno.com/v2/layers" \
  -d '{
    "slug": "my-service-shared",
    "env_vars": [
      {"key": "DATABASE_URL", "value": "postgres://...", "secret": true},
      {"key": "API_KEY", "value": "sk-...", "secret": true}
    ]
  }'

# 创建一个使用该层的应用
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  "https://api.deno.com/v2/apps" \
  -d '{
    "slug": "my-service-auth",
    "layers": ["my-service-shared"],
    "labels": {"service": "my-service"},
    "config": {
      "install": "deno install",
      "runtime": {
        "type": "dynamic",
        "entrypoint": "main.ts"
      }
    }
  }'

当某个层的环境变量更新时,使用该层的所有应用会立即获取到 这些变化。

迁移清单 Jump to heading

  1. 在 Deno Deploy 仪表板中创建一个 v2 组织令牌ddo_ 前缀)。
  2. 每个函数创建一个应用,而不是将多个函数部署到一个 项目中。使用标签对相关应用进行分组。
  3. 设置层,用于在多个函数之间共享环境变量。
  4. 更新部署请求:
    • entryPointUrl 移动到 config.runtime.entrypoint
    • config.install 设置为 "deno install"
    • envVars 对象转换为 env_vars 数组,或设置在应用/层上
    • 为资源添加 kind: "file"
  5. 更新构建日志尾随,改为使用 GET /revisions/{id}/progress(SSE) 而不是轮询。
  6. 更新日志查询:
    • since/untilstart/end
    • warningwarn
    • 日志响应体中的 timetimestamp
    • 处理 {logs: [...], next_cursor: ...} 响应包装
  7. 分页方式更新:从基于页码改为基于游标。
  8. 更新状态值pendingqueuedsuccesssucceeded
  9. 将字段名从 camelCase 更新为 snake_case。

Last updated on

你找到了你需要的东西吗?

编辑此页面
隐私政策