计算

Fastly Compute@Edge 的 Swift 运行时

开始入门

使用 executable 模板创建一个新的 swift 包

swift package init --type executable

安装 Compute 运行时

.package(url: "https://github.com/swift-cloud/Compute", from: "3.0.0")

将其添加为目标依赖项

.executableTarget(
    name: "MyApp",
    dependencies: ["Compute"]
)

部署

将 Swift 应用程序部署到 Fastly 最简单的方法是通过 Swift Cloud

Swift Cloud 是一个完全托管的平台即服务,用于将 SwiftWasm 应用程序部署到 Fastly。您可以连接您的 Github 帐户,一键部署您的应用程序。

文档

完整的文档仍在积极开发中

https://compute-runtime.swift.cloud/documentation/compute/

示例应用

以下是在 Compute@Edge 上 Swift 应用程序的样子

import Compute

try await onIncomingRequest { req, res in
    let fetchResponse = try await fetch("https://httpbin.org/json", .options(
        headers: ["user-agent": "swift-compute-runtime"]
    ))
    let text = try await fetchResponse.text()
    try await res.status(200).send(text)
}

SwiftWasm

Compute@Edge 上的 Swift 得益于令人难以置信的 SwiftWasm 项目,但可能不是您想象的方式。Web Assembly 正在掀起波澜,成为 Web 应用程序开发的新高性能环境,但它也为 Fastly Compute@Edge 等云计算平台提供动力。部署到 Fastly 涉及将您的代码编译为 Web Assembly,然后将其部署到 Fastly 服务。这可以通过 GitHub Actions 完成,但部署代码最绝对简单的方法是通过 Swift Cloud。 Swift Cloud 在 AWS Fargate 实例上构建您的代码,然后使用 Binaryen 优化 WASM 二进制文件。Fastly 服务在后台进行管理,我们使集成 Edge 字典、后端和环境变量等内容变得非常简单。

路由

Compute 包包含一个基于 Vapor 的 routing-kit 的 Express 风格的路由器。以下是一些使用路由器的基本方法

GET 路由

import Compute

let router = Router()

router.get("/status") { req, res in
    try await res.status(.ok).send("OK")
}

router.get("/user/:name") { req, res in
    let name = req.pathParams["name"] ?? ""
    let text = "Hello, \(name)!"
    try await res.status(.ok).send(text)
}

try await router.listen()

POST 路由

import Compute

struct User: Codable {
    let name: String
}

let router = Router()

router.post("/user") { req, res in
    let user = try await req.body.decode(User.self)
    try await res.status(.created).send(user)
}

try await router.listen()

获取数据

如今 WebAssembly 的主要缺点之一是没有标准化的套接字处理方式。因此,SwiftWasm 无法访问某些 Foundation 类,例如 URLSession。这需要每个运行时提供自己的网络层,直到 WASM 规范中引入标准化的线程和套接字模型。

Compute 包提供了 fetch(_ url: String) 函数,用于发送异步 HTTP 请求。该实现很大程度上模仿了 HTML5 fetch() 规范,包括对流式请求和响应体、async/await 和 Codable 支持的完整支持。

重要提示: 为了使用 fetch,您必须预先定义您将要调用的主机名。例如,如果您正在与 Stripe API 集成,则必须在您的 Fastly 服务中预先定义 api.stripe.com。Swift Cloud 也使得在创建项目时非常容易定义所有外部源站。我们真诚地希望这是 Fastly 平台的短期限制,并相信他们正在研究一种机制,无需预先定义即可调用任意后端。

GET 请求

let data = try await fetch("https://httpbin.org/json").json()

POST 请求

let res = try await fetch("https://httpbin.org/json", .options(
    method: .post,
    body: .json(["name": "Andrew"])
))

代理请求

Compute 包的一个非常强大的功能是能够代理到另一个源站。与单区域源站相比,Fasty 的边缘平台是一个全球分布的 CDN,可提供前所未有的性能。使用 Compute,您可以将功能齐全的 CDN 放在您的源站前面,以执行诸如强制 HTTPS、启用 HTTP/3、提供强大的源站故障转移以及更多操作。

/// req: IncomingRequest, res: OutgoingResponse
let data = try await fetch(req, origin: "https://httpbin.org", .options(
    cachePolicy: .ttl(10, staleWhileRevalidate: 30)
))
try await res.proxy(data)

缓存

Compute 包提供对 Fastly 缓存 API 的访问,允许您在请求期间缓存和检索任意数据

let data = try await Cache.getOrSet("my-page") {
    let res = try await expensivePageRender()
    return (res, .ttl(60))
}

try await res
    .status(200)
    .header(.contentLength, "\(data.contentLength)")
    .send(data.body)