Chapter 01

Vapor 入门

搭建 Swift 服务端开发环境,理解 NIO 非阻塞模型,用 10 行代码运行第一个 Vapor 服务。

为什么选择 Swift 写服务端?

在 Node.js、Go、Python 百花齐放的服务端世界,Swift 凭借独特的优势正在悄然崛起。对于 iOS/macOS 开发者而言,用同一门语言贯通前后端是最直接的诉求——你不需要在 TypeScript 和 Swift 之间来回切换,可以直接在服务端和客户端共享数据模型(DTO)、验证逻辑甚至部分业务代码。

Swift 的类型系统是所有主流语言中最严格的之一。编译器会在编译期捕获绝大多数错误,运行时 nil 崩溃几乎不存在(可选值 Optional 的强制处理),这使得 Swift 服务端应用在生产环境中的稳定性极高。与 Go 相当的性能、比 Python 快十倍以上的执行速度,让 Vapor 完全能够承载中大型业务场景。

Swift 服务端的优势

  • 类型安全,编译期排错
  • 与 iOS/macOS 共享模型代码
  • async/await 原生并发
  • 内存安全,无垃圾回收停顿
  • SwiftPM 完善的包管理

适合的业务场景

  • Apple 平台 App 的专属后端
  • 高并发 API 服务
  • 微服务架构中的单个服务
  • 全栈 Swift 团队
  • 需要共享 Swift Package 的项目

核心概念词典

在动手之前,先理解 Vapor 生态的几个基础名词。这些概念贯穿整个课程,是后续所有内容的地基。

Vapor
Swift 生态中最主流的 Web 框架,基于 SwiftNIO 构建,提供路由、ORM(Fluent)、认证、WebSocket 等完整服务端能力。当前稳定版本为 Vapor 4,要求 Swift 5.8+。
Vapor Toolbox
Vapor 的命令行工具(CLI),通过 vapor new 快速脚手架项目、vapor run 启动服务、vapor build 编译。安装方式:brew install vapor
SwiftNIO
Apple 开源的异步网络框架,是 Vapor 的底层运行时。NIO 代表 Non-blocking I/O(非阻塞 I/O),采用事件驱动模型,单线程可处理数千并发连接,与 Node.js 的 libuv、Java 的 Netty 同属一类。
EventLoop
NIO 的核心调度单元,每个 EventLoop 运行在单个线程上,不断轮询 I/O 事件(网络读写、定时器),通过回调驱动代码执行,避免线程阻塞等待。Vapor 启动时会创建与 CPU 核心数相等的 EventLoop 线程池。
Package.swift
SwiftPM(Swift Package Manager)的项目配置文件,声明依赖项、编译目标和版本要求。类似于 Node.js 的 package.json 或 Go 的 go.mod,是 Swift 生态的标准包描述格式。
Application
Vapor 应用的核心对象,负责管理整个服务的生命周期——启动、路由注册、中间件配置、数据库连接池、关闭。所有配置操作都通过 app 实例完成。

安装与项目创建

Vapor 的安装非常简单,通过 Homebrew 一条命令完成 Toolbox 的安装。Toolbox 本身是一个 Swift 命令行工具,安装后提供 vapor 命令。

环境要求(Swift 6) 本教程使用 Swift 6 + Vapor 4.99.x,要求 macOS 14 (Sonoma) 或更高版本。Swift 6 开启严格并发检查,是 Apple 推荐的生产标准。运行 swift --version 确认版本 ≥ 6.0,或通过 Xcode 15.3+ 自带的 Swift 6 工具链使用。Linux 部署同样支持 Ubuntu 22.04/24.04。
# 安装 Vapor Toolbox
brew install vapor

# 验证安装
vapor --version

# 创建新项目(交互式,会询问数据库等配置)
vapor new HelloVapor

# 进入项目目录
cd HelloVapor

# 生成 Xcode 项目(可选,用于在 Xcode 中开发)
open Package.swift

# 运行开发服务器(默认监听 8080 端口)
swift run

项目结构详解

执行 vapor new 后,Vapor 会生成一套标准项目骨架。理解每个文件的职责是掌握框架的第一步:

HelloVapor/
├── Package.swift          ← 依赖声明(Vapor、Fluent 等)
├── Sources/
│   └── App/
│       ├── entrypoint.swift   ← main 入口,创建 Application
│       ├── configure.swift    ← 应用配置(数据库、中间件、服务注册)
│       └── routes.swift       ← 路由注册入口
│       └── Controllers/       ← 控制器目录(自行创建)
│       └── Models/            ← 数据模型目录(自行创建)
│       └── Migrations/        ← 数据库迁移目录(自行创建)
└── Tests/
    └── AppTests/
        └── AppTests.swift     ← 集成测试

entrypoint.swift 是程序的入口点,负责初始化 Application 对象并调用 configureroutesconfigure.swift 是注册所有服务的地方,包括数据库驱动、中间件、认证配置等。routes.swift 是路由注册的入口,但实际路由往往分散到各个 RouteCollection 中。

请求生命周期

理解一个 HTTP 请求从客户端到达 Vapor 服务再返回响应的完整路径,对于调试和性能优化至关重要。Vapor 基于 NIO 的非阻塞模型与传统的"每请求一线程"模型有本质区别。

Client (Browser/App) │ │ HTTP/HTTPS TCP 连接 ▼ ┌─────────────────────────────────────────────┐ │ SwiftNIO EventLoop Pool │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ ELoop-0 │ │ ELoop-1 │ │ ELoop-2 │ ... │ │ └────┬────┘ └────┬────┘ └────┬────┘ │ └───────┼─────────────┼────────────┼──────────┘ │ │ │ ▼ (某个 EventLoop 处理该请求) ┌───────────────────────────────┐ │ Middleware Stack │ │ ErrorMiddleware │ │ └─ CORSMiddleware │ │ └─ LogMiddleware │ │ └─ RouteHandler │ └───────────────────────────────┘ │ ▼ ┌──────────────────┐ │ Router (Trie) │ ← 匹配路径 /users/:id └────────┬─────────┘ │ ▼ ┌──────────────────┐ │ Controller │ ← 业务逻辑 │ └─ DB Query │ ← async 数据库操作 └────────┬─────────┘ │ ▼ HTTP Response → 回传给 Client

关键点在于:整个流程中,EventLoop 线程永远不会阻塞等待。数据库查询、网络请求等 I/O 操作全部通过 async/await 挂起,线程在等待期间可以处理其他请求。这就是 NIO 高并发的核心秘密——用少量线程(通常等于 CPU 核心数)服务海量并发连接。

第一个 Hello World

打开 Sources/App/routes.swift,用最简单的代码注册一个路由:

import Vapor

func routes(_ app: Application) throws {

    // GET / → 返回纯文本
    app.get { req async in
        "Hello, Vapor!"
    }

    // GET /hello/:name → 路径参数
    app.get("hello", ":name") { req async throws -> String in
        let name = try req.parameters.require("name")
        return "Hello, \(name)!"
    }

    // GET /json → 返回 JSON(自动序列化)
    app.get("json") { req async -> Response in
        let data = ["message": "Hello JSON", "framework": "Vapor 4"]
        return try .init(status: .ok, headers: ["Content-Type": "application/json"],
                         body: .init(data: JSONEncoder().encode(data)))
    }
}
// configure.swift — 最简配置
import Vapor

public func configure(_ app: Application) async throws {
    // 端口配置(默认 8080)
    app.http.server.configuration.port = 8080

    // 注册路由
    try routes(app)
}
# 运行服务
swift run

# 另开终端测试
curl http://localhost:8080/
# → Hello, Vapor!

curl http://localhost:8080/hello/World
# → Hello, World!
开发小技巧 使用 swift run --enable-test-discovery 可以同时跑测试。开发阶段推荐安装 watchexec 工具配合自动重启:watchexec -e swift swift run,保存代码后自动重新编译运行。

Package.swift 依赖配置(Swift 6)

Vapor 项目通过 Package.swift 声明所有外部依赖。本教程使用 swift-tools-version:6.0,开启 Swift 6 严格并发检查(Strict Concurrency)。相比旧版,主要变化是顶层声明 swiftLanguageVersions: [.v6] 并在 swiftSettings 中启用并发特性:

// swift-tools-version:6.0
import PackageDescription

let package = Package(
    name: "MyVaporApp",
    platforms: [.macOS(.v14)],
    dependencies: [
        // Vapor 4.99.x:正式支持 Swift 6 并发模型
        .package(url: "https://github.com/vapor/vapor.git", from: "4.99.3"),
        // Fluent ORM(Swift 6 兼容版本)
        .package(url: "https://github.com/vapor/fluent.git", from: "4.12.0"),
        // PostgreSQL 驱动
        .package(url: "https://github.com/vapor/fluent-postgres-driver.git", from: "2.10.0"),
        // JWT 支持
        .package(url: "https://github.com/vapor/jwt.git", from: "4.2.2"),
    ],
    targets: [
        .executableTarget(
            name: "App",
            dependencies: [
                .product(name: "Vapor", package: "vapor"),
                .product(name: "Fluent", package: "fluent"),
                .product(name: "FluentPostgresDriver", package: "fluent-postgres-driver"),
                .product(name: "JWT", package: "jwt"),
            ],
            swiftSettings: swiftSettings
        ),
        .testTarget(
            name: "AppTests",
            dependencies: [
                .target(name: "App"),
                .product(name: "XCTVapor", package: "vapor"),
            ],
            swiftSettings: swiftSettings
        )
    ],
    // Swift 6 语言模式:开启严格并发检查
    swiftLanguageVersions: [.v6]
)

// Swift 6 并发特性设置
var swiftSettings: [SwiftSetting] { [
    .enableUpcomingFeature("DisableOutwardActorInference"),
    .enableExperimentalFeature("StrictConcurrency"),
] }
Swift 6 严格并发的意义 Swift 6 最重要的变化是把并发安全提升为编译期强制要求。编译器会检查所有跨并发边界传递的值是否符合 Sendable,防止数据竞争在运行时出现。swiftLanguageVersions: [.v6] 告诉 SwiftPM 用 Swift 6 语言模式编译,StrictConcurrency 则进一步开启实验性的严格并发规则。Vapor 4.99.x 专门针对 Swift 6 做了适配,路由闭包签名变为 @Sendable
本章小结 本章建立了 Vapor 开发的基础认知:Swift 服务端的独特优势、NIO 非阻塞模型的工作原理、项目结构的职责划分,以及第一个可运行的 Hello World 服务。下一章将深入路由系统,学习如何用 Trie 树高效匹配请求,构建完整的 RESTful API 结构。