跳至主要内容
Deno 2 终于来了 🎉️
了解更多
Subhosting

Deno 子托管更灵活的域名关联功能介绍

子托管 让您能够轻松地在安全、托管的沙箱中安全运行来自多个客户的不可信 JavaScript 代码。子托管有许多用例,例如 为其用户提供边缘功能在靠近用户的位置托管电子商务店面 等 - 这一切都无需担心安全性和维护生产基础设施。

在托管用户代码时,有时您希望他们的部署可以通过简洁的自定义域名(如 user1.yourcompany.com)公开访问。现在,使用我们新的、更灵活的域名关联功能,您可以更轻松地管理用户部署中的自定义域名。这使您能够以编程方式管理域名映射并将自定义域名附加到部署中,方法是通过子托管 API。

在这篇文章中,我们将介绍

在深入了解如何使用 API 之前,让我们回顾一下此功能现在支持的内容。

组织范围的通配符子域名

现在,您可以将同一个通配符域名下的不同子域名分配给不同的部署。例如,给定 *.example.com 通配符域名,您现在可以将 foo.example.com 分配给一个部署,并将 bar.example.com 分配给另一个部署。这种灵活性允许更复杂的部署策略,并更容易管理资源。

用于简化域名管理的变量

为了使以编程方式管理和引用用户部署更简单,现在在您指定要与部署关联的域名时会公开两个变量

  • {deployment.id}:部署的唯一标识符。
  • {project.name}:部署所属项目的名称。

这些可以与任意字符串组合,只要它们是有效的域名并被您在替换后注册的通配符域名覆盖。例如,您可以指定一个域名,例如

  • {deployment.id}.example.com
  • {project.name}.example.com
  • {project.name}-{deployment.id}.example.com
  • foo-{deployment.id}.example.com
  • foo-{deployment.id}-{project.name}.example.com

这些变量也可以与 deno.dev 域名结合使用,但在这种情况下,仅允许以下两种格式

  • {project.name}-{deployment.id}.deno.dev
  • {project.name}.deno.dev

这些增强功能提供了更好的自定义和自动化功能,使以编程方式管理和引用部署变得更加容易。

让我们看一下如何通过示例来实践这些功能。

如何附加和分离自定义域名

在将自定义域名附加到部署之前,您首先需要使用 POST /organizations/{organizationId}/domains 端点注册您的自定义域名。

import { assert } from "jsr:@std/assert/assert";

const orgId = "your-organization-id";
const orgToken = "your-organization-token";

const res = await fetch(
  `https://api.deno.com/v1/organizations/${orgId}/domains`,
  {
    method: "POST",
    body: JSON.stringify({
      domain: "*.example.com",
    }),
    headers: {
      "Content-Type": "application/json",
      "Authorization": `Bearer ${orgToken}`,
    },
  },
);

assert(res.ok);

此调用的响应主体包含 dnsRecords 字段,它是一个您可以用来设置命名服务器的 DNS 记录列表。

下一步是为域名颁发 TLS 证书。虽然您可以通过 上传证书 来完成,但您也可以通过 POST /domains/{domainId}/certificates/provision 来配置 TLS 证书。

import { assert } from "jsr:@std/assert/assert";

const orgToken = "your-organization-token";
// Domain ID you got from the previous step
const domainId = "your-domain-id";

const res = await fetch(
  `https://api.deno.com/v1/domains/${domainId}/certificates/provision`,
  {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${orgToken}`,
    },
  },
);

assert(res.ok);

现在您已经准备就绪 - 让我们使用 POST /projects/{projectId}/deployments 创建一个新部署。

import { assert } from "jsr:@std/assert/assert";

const projectId = "your-project-id";
const orgToken = "your-organization-token";

const res = await fetch(
  `https://api.deno.com/v1/projects/${projectId}/deployments`,
  {
    method: "POST",
    body: JSON.stringify({
      entryPointUrl: "main.ts",
      assets: {
        "main.ts": {
          kind: "file",
          content: 'Deno.serve(() => new Response("hello"));',
        },
      },
      envVars: {},
      domains: [
        "foo.example.com",
        "{deployment.id}.example.com",
        "{project.name}-{deployment.id}.deno.dev",
      ],
    }),
    headers: {
      "Content-Type": "application/json",
      "Authorization": `Bearer ${orgToken}`,
    },
  },
);

assert(res.ok);

请注意 JSON 负载中的新 domains 字段,它是一个自定义域名的数组,这些自定义域名将在部署成功创建后附加到部署。另外,您也可以在此处使用 命名变量 在域名中,这些变量将变为实际值。

假设新创建的部署 ID 为 chonky-dog-57,位于项目 my-project 下。在我们的示例中,以下域名都将路由到这个新创建的部署

  • https://foo.example.com
  • https://chonky-dog-57.example.com
  • https://my-project-chonky-dog-57.deno.dev

如果我们想将自定义域名附加到现有部署,我们可以使用 PUT /deployments/{deploymentId}/domains/{domain}

import { assert } from "jsr:@std/assert/assert";

const deploymentId = "chonky-dog-57";
const orgToken = "your-organization-token";

const extraDomain = "prefix-{project.name}.example.com";

const res = await fetch(`/deployments/${deploymentId}/domains/${extraDomain}`, {
  method: "PUT",
  headers: {
    "Authorization": `Bearer ${orgToken}`,
  },
});

assert(res.ok);

现在,访问 https://prefix-my-project.example.com 的任何人都将被重定向到现有的 chonky-dog-57 部署。

请注意,只要将域名附加到部署,它就会自动从任何先前的部署中分离。

我们也可以使用 DELETE /deployments/{deploymentId}/domains/{domain} 手动将域名从部署中分离。

import { assert } from "jsr:@std/assert/assert";

const deploymentId = "chonky-dog-57";
const orgToken = "your-organization-token";

const res = await fetch(
  `/deployments/${deploymentId}/domains/foo.example.com`,
  {
    method: "DELETE",
    headers: {
      "Authorization": `Bearer ${orgToken}`,
    },
  },
);

assert(res.ok);

现在,域名 https://foo.example.com 将不再指向 chonky-dog-57 部署。

下一步

子托管 仍然是希望运行用户代码而无需担心安全或维护生产基础设施的组织的绝佳选择。

我们将继续投入资源,使子托管成为运行第三方不可信代码的最简单方式,以便您可以专注于为最终用户提供价值。

🚨️ 您想在不从头开始构建的情况下安全运行用户不可信代码吗?

查看 Deno 子托管,您可以在几分钟内在一个安全、托管的沙箱中安全运行来自多个用户的 JavaScript 代码。