Slug edward jiang cover

令世人惊叹的服务器端 Swift!

时至今日,Swift 已然演变成了一门开源、跨平台的编程语言,有许多个团队正在竞相利用 Swift 语言能够用于 Web 开发。其中最主要的框架分别是:Perfect、Vapor 以及 IBM 的 Kitura,它们在 GitHub 上已经获得了超过 13,000 个星星了,并且热度依然不减!接下来我们将会聊一聊这些框架的优缺点,并且介绍如何入门服务器端 Swift 开发。(其中的几个框架仅支持 Swift 3!)跟随 Edward 一起来现场编程,并且将一个 Swift 应用部署到云端!


概述 (0:00)

我在 Apple 发布 Swift 之后就开始使用 Swift 了。那时候我还不是一名 iOS 开发者(当时我只是一个对什么都感兴趣的开发者而已),但是 Swift 发布之后,我瞬间就爱上了这门语言(因此,这也就是为什么两年半之后,我才能在此时此刻站在这里为大家演讲)。

我就职于 Stormpath,这是一家从事用户管理以及用户存储系统的公司。如果您打算构建一个 Web 应用程序或者后端服务,那么不妨考虑使用 Storempath 来帮助您构建一些不错的东西。在此之前,我还工作于 PadMapper(我开发了这款 iOS 应用),成立了 StudentRND 这样一个非营利性组织,负责教授学生技术以及如何编写代码。

我打算以一个旁观者的角度来讨论服务端 Swift 开发,比较各个框架以及服务端 Swift 开发所处的位置。我首先简要概述下服务端 Swift 生态系统,介绍几个流行的服务端框架,以及一个简单的 “Hello,World!”应用程序,接着通过现场编码演示如何部署服务端 Swift 开发环境,编写一个 “Hello,World!”应用,然后将其部署到 Heroku 云服务器上。

为什么使用 Swift 来开发 Web? (1:58)

我们大多数人都有过使用 Swift 为 iOS 或 Mac OS X 开发应用程序的经历(包括瞎折腾)。随着 12 月份 Swift 正式开源,开发者已经开始尝试服务端开发,使用 Swift 构建 web 应用程序。那么问题来了,为什么我们要用 Swift 进行 web 开发呢?

  1. 相比较其他一些流行的 web 编程语言(Python,Ruby),Swift 是一门快速和安全的语言。它可以执行本机代码 (native code)。
  2. 这是一门强类型语言,引入了可选类型,你可以确保永远不会有任何空指针的错误。
  3. 不同于其他安全语言(Java 或 C#),Swift 表达更加清晰。这是一个不错方式帮助我们快速构建应用,同时又不用操心一些编译器的事情: 1)构建一款没有崩溃的应用程序,2)缩短应用开发周期。
  4. 开发者热衷 Swift。移植 Swift 到更多平台想想都让人兴奋。

一家开发 iOS 应用程序的公司赞助了我的一个朋友;他们使用 PHP 的 Laravel 打造应用后台,同时使用 Swift 语言开发 iOS 应用程序。此外,该公司还赞助了服务端 Swift 开发,因为他们希望自己的前端开发人员(移动端程序员)和服务端开发人员(接口制定者)之间能够具有更多灵活性。鼓励后端开发者学习 Swift 不仅能提高效率,又能同时推动前端和后端的发展。

接下来我会介绍四个主要的服务端 Swift 开发框架,分别是:PerfectVaporKituraZewo

Perfect (4:40)

如果你对服务端 Swift 生态系统有所了解,想必都听说过 Perfect 开源框架。 Perfect 起初是由来自加拿大的团队开发,仅有 2、3 个成员。去年10月份或者11月份的时候,我记得他们四处奔波参加活动,“随着 Swift 开源代码,你将能够依托它在服务器上构建一些很酷的东西。”

Receive news and updates from Realm straight to your inbox

Perfect 目前在 Github 上收获星星最多:7200+ 星星(像 Rails,Expressjs,JDjango 等最流行的 web 框架在 Github 上的星星大多在 2 万到 3 万之间)。不难看出服务端 Swift 开发极具潜力。他们的目标是将 Swift 做的和 Rails 一样。团队正试图构建一个完整的框架,从而允许你使用 Swift 做任何事。此外,框架还集成了一套强大的功能特性。然而, Rails 整体略显庞大(你必须以 Rail 的方式做一些事情)。Perfect 也同样存在这样的问题:它具有非常棒的功能,但仅向开发者提供寥寥几个方法用以开发应用。

首先让我们看看 Perfect 的相关代码(请见视频)。你可以试着运行应用程序,Perfect 工程中自带了一个 http 服务器,你可以用来运行 fastCGI 模块并将其连接至 Apache 或 NGINX。接着,你可以编写一个模块供 Perfect 服务器运行。这里,我们将构建一个 “ Hello,World!” 应用程序。当用户访问 localhost 时,浏览器页面输出 “Hello,World!”。Perfect 要求你在模块里注册一个名为 PerfectServerModuleInit 的全局函数。你可以在函数中初始化路由表,为每个路由地址绑定一个路由处理闭包。在路由处理程序中,你可以返回一个实现了 handleRequest 方法的类。我们会将 ”Hello,World!“ 文字追加到 Response 的文本段中,同时还要告诉它:“这个请求已经完成”。

我一直使用 Node.js 构建服务端应用,在此之前是 PHP。 以我对语法的偏好来说感觉有点奇怪,但它完全能胜任工作。

Vapor (7:30)

Vapor 框架在 Github 上受欢迎程度位居第二(4000+ 星星),它是受 Laravel 启发。Laravel是一套简洁、优雅的 PHP Web开发框架,拥有非常清晰的语法表达方式。

当我刚开始入坑服务端 Swift 开发之时,他们就为此提供了大量的文档。Vapor 的其中一位缔造者 Tanner 是我早先提到的家伙:公司赞助了 Vapor 两位程序员进行全职开发。经过这两位开发者的不懈努力,他们成功构建了一个伟大的 Web 框架(有点像 Perfect - Perfect 团队筹集了150万美元来继续打造和商业化服务器端 Swift 开发) 。

让我们来看看 Vapor 的示例代码(见视频),同样是构建一个“Hello,World!” 应用程序,我们导入了 Vapor 模块,并创建一个应用程序对象。于此同时我们需要为 “/” 路由地址绑定一个处理程序,返回字符串“Hello,World!”。然后,我们启动应用程序,…这里所做的工作和 Perfect 其实是一样的,最后均构建了一个基本的 “Hello,World!” 应用程序。

我喜欢这个例程,因为它展现了 Swift 语言的表达性。这里,我们返回了一个 “Hello,World!” 字符串,但是 Perfect 中定义了协议返回一个 response。你不必只返回一个字符串,可以返回例如一个模板引擎或 JSON 数据,之后应用程序中再转换成正确的数据。

IBM Kitura (9:28)

Kitura 由 IBM 开发维护,项目始于今年二月底。它在 Github 上流行程度位居第三(3000+星星) 。IBM 收购了一家名为 Strongloop 的公司,曾是 Express.js 的维护者 - 这并不奇怪,Kitura 同样也是 Express.js 风格的框架。 从语法上来看 Kitura 类似于 Vapor。我们首先导入 Kitura 库,创建一个路由对象,然后将处理程序绑定到 “/” 路由地址上。当运行 http 服务器时,会返回给我们一个包含 “Hello,World!“ 的响应。

Kitura 语法近似于 Vapor。但在很多使用方式都有所不同,但假如你熟悉 Express,这看起来会很亲切。

Zewo (10:35)

不同于其他三者,Zewo 在 Github 上并非是第四流行框架(1000+星星)。虽然已经存在很多不同的 Swift web 框架(例如 Rails 的 Swift ,Sails 的 Swift ,Swift Express 等等),不过 Zewo 则完全不同,它是一个超级模块:它由50个不同的包组成,你可以选择部分包来构建你的 web 应用程序。如果你想搭建自己的 http 服务器,或者构建一个 web 应用程序框架却不想编写每一个组件时,你可以使用 Zewo 的不同库来私人定制属于你的 Web 服务器和 Web 应用程序框架。此外,由于 Swift 开源了代码,Zewo 的基础构件可以同 Vapor 互换。这也是为什么本次演讲主题是『令世人惊叹的服务器端 Swift』。

Open Swift (11:35)

Open Swift 小组维护着一个名为 S4 的项目 - S4 代表着服务端 Swift 开发标准。他们一直沿用一套通用的中间件工作,包括请求、响应和服务器……当为服务端 Swift 应用程序构建中间件时,我们会组合不同的协议。当然你可以单独为 Vapor 和 Zewo 构建部分中间件。此外,我还在 Slack 频道中看到来自 IBM Kitura 和 Perfect 的开发者。接下来的几个月里,它有望成为所有服务器端框架的标准。

Zewo 语法与 Kitura 和 Vapor 很近似。由于其超强的模块化特性,我们必须导入两个不同的模块才能进行工作。首先我们创建一个路由对象,然后绑定一个处理程序给 /路由地址,当我们访问时会得到“Hello,World!” 响应文字。这里我创建了一张简明表从功能特性和 Swift 版本来对比这些框架。

所有这些框架都提供了一个基本的模板设置引擎。 Kitura 提供的一些外链同样还包括 ORM;你可以使用它来连接数据库以及转换成 Swift 对象。如果你打算开始尝试,推荐使用 Perfect,Vapor ,Zewo 和 Kitura 四个框架中的一个。尽管 Kitura 起步较晚(二月下旬才开始),但他们仍在不断追赶当中。以上提到的这些都值得你去捣鼓一番,将会非常有趣。

上述这些框架使用的 Swift 版本也各有不同(Swift2.2:Perfect。不同日期的 Swift 3版本:Vapor,5月31日;Kitura,5月9日;Zewo,4月12日)。你不禁要问,为什么会有这么多的 Swift 版本? 其原因归咎于: Swift 包管理器 (Package Manager)。

Swift 包管理器 (14:28)

Swift Package Manager 仅支持 Swift 3 开发预览版。部分原因是 Swift 3 最初看起来类似于 Swift 2(你所要做的就是建立一个 Swift 3 的快照)。然而,当前发布版本在一个半月前的基础上又进行了大刀阔斧地改动,现在所有的项目都是在不同的 Swift 3 版本上。此外,Foundation 框架还没有完全实现。许多框架开发者正在等待 Swift 3 发布以便用于生产环境。

接下来我会快速向你们演示编码第一个 Vapor 应用例程,首先部署 Swift 开发环境,接着编写一个之前展示过的 “Hello,World!” 例程,并部署到 Heroku 上。快速而又简单

安装 Swift 版本管理器 (15:53)

首先,我们将安装 Swiftenv。如果你不太熟悉 Python 或者 Ruby 语言(也没有关系),因为在很多其他编程语言中,社区都会提供一款工具帮助你管理当前使用语言的版本。Swift 亦是如此,因为版本更新太过频繁,你要面对诸多不同版本的 Swift 快照。

首先,我们需要安装 Swiftenv

$ git clone https://github.com/kylef/swiftenv.git
~/.swiftenv

$ echo 'export SWIFTENV_ROOT="$HOME/.swiftenv"' >>
~/.bash_profile
$ echo 'export PATH="$SWIFTENV_ROOT/bin:$PATH"' >>
~/.bash_profile
$ echo 'eval "$(swiftenv init -)"' >> ~/.bash_profile

Kyle Fuller 编写了 Swiftenv ,他是 Swift 生态系统中一位多产的贡献者。我们所要做的是克隆他的代码仓,移动到我们自己的目录,设置一些环境变量,并确保添加环境变量到我们的 bash 配置文件中。

安装 Swift 5-31 (17:10)

我们使用 Swiftenv 安装最新版本的 Swift 开发预览版(由于我们使用 Vapor 开发,所以需要安装 5月 31 号的快照):

$ swiftenv install DEVELOPMENT-SNAPSHOT-2016-05-31-a

初始化项目 (18:12)

我们新建一个文件夹用作目录(命名 SwiftLangHelloWorld ),并使用 Swiftenv 切换本地环境到下载好的开发预览版。这条命令并非完全必要的,但如果之后你使用了多个不同版本的 Swift 快照,那么有可能被默认设置为其他版本。这个操作会创建一个名为 Swift-Version 的文件(用于明确 Swift 版本)。这样就能确保项目中运行的 Swift 版本正是我们想要的。

$ mkdir HelloWorld
$ cd HelloWorld
$ swiftenv local DEVELOPMENT-
SNAPSHOT-2016-05-31-a

$ swift package init --type executable
Creating executable package: HelloWorld
Creating Package.swift
Creating Sources/
Creating Sources/main.swift
Creating Tests/

接下来,我们将使用 Swift Package Manager 提供的命令,在终端中输入 swift package init --type executable。这样会为 Swift Package Manager 创建一个基本目录结构,并帮助我们开始构建应用程序。首先,我们将新建一个 package.swift 文件,用于管理项目中的所有依赖关系;接着,我们新增一个 main.swift 文件(这里我们将运行大部分代码)。

package.swift 中加入 Vapor (18:58)

import PackageDescription

let package = Package(
  name: "HelloWorld",
  dependencies: [
    .Package(url: "https://github.com/qutheory/vapor.git", majorVersion: 0, minor: 10)
  ]
)

现在我们创建了这个项目,并将 Vapor 作为项目依赖添加到 package.swift 中, Swift Package Manager 会下载所有依赖库并添加到我们的 Xcode 文件中。我使用 Sublime 编辑器打开项目,你可以看到 package.swift 文件内容。这是 Swift 语言的子集。所有这一切都是默认的,我们导入包描述并创建了这个包对象。我将添加 Vapor 作为我们的依赖,保存,接着使用 Swift Package Manager 做两件事 1)下载依赖文件 2)生成 Xcode 文件。

在 Xcode 中打开 (20:40)

如果运行 swift build swift package generate-xcodeproj 这条命令,将开始克隆所有 Vapor 的依赖文件,检查 Vapor 的依赖树,确保我们拥有所有依赖文件。命令会下载所有依赖文件,最后生成一个Xcode 工程文件。下载依赖文件先从 Vapor 的代码仓开始,紧接着是 S4 项目代码,也就是前面提及的服务端 Swift 标准,以及所有其他与 Vapor 有依赖关系的文件。

Swift Package Manager 并没有一个中央存储代码仓,所有我们要做的是指向 git 代码仓地址,然后设置 package.swift 文件中的标签来确定下载哪些文件。

$ swift package generate-xcodeproj
$ open HelloWorld.xcodeproj

现在我们创建了工程,请使用 Xcode 工具打开新生成的 SwiftLangHelloWorld.xcodeproj 项目。Xcode 项目包含了一个 main.swift 文件。我们会向里面写入一条语句:print ("Hello World!")。请拷贝之前的代码到文件中。点击运行,终端输出“Server starting at 0.0.0.0:8000”。如果你在浏览器中访问 localhost:8000 地址,会输出Hello, World!(👏)。可以看到使用 Vapor 上手服务端 Swift 开发相当容易。

现在…部署应用程序到服务端吧! (22:30)

$ git init
$ heroku create
$ heroku buildpacks:set https://
github.com/kylef/heroku-buildpack-swift
$ echo 'web: HelloWorld --port=$PORT'
>> Procfile

$ git add .
$ git commit -m "created project"
$ git push heroku master

Heroku 是一个服务平台。你可以将代码初始成一个 Git 仓库,然后使用 git 指令将其推送到 Heroku 上。Heroku 会自动检测你上传的应用程序类型,编译并运行它。然而,Heroku 无法自动识别 Swift,不过你可以设置一个自定义 buildpack 用于检测,构建和运行项目

在命令行中,我们输入 heroku create 命令创建一个 Git 代码仓。当你安装 Heroku 时,可以下载一个命令工具帮助你实现自动化。它会把 Heroku 当做远程库添加到 Git 配置中,这样我们就可以将 Heroku 作为目标进行推送了。然后,我们需要运行 heroku buildpack:set命令,设置成 Kyle Fuller 为 Swift 写的 Heroku buildpack 。这就是告诉 Heroku ,”如何检测应用程序,然后如何构建和运行它”。

接下来我们需要做的是创建一个 Procfile 文件。对于 Heroku 来说,除非是很常见的框架,你都需要告诉 Heroku 如何运行你的应用程序。我们仅用web: HelloWorld --port=$PORT一行代码创建了 Procfile 文件。$PORT 是环境变量中的端口参数。Heroku 将其作为自定义端口运行它,并把它放置到后面的负载平衡器[你需要把这里更改为 SwiftLangHelloWorld(which would not be what this is),web: 该端口为SwiftLangHelloWorld ]。我们将添加所有的文件,同时创建并推送到 Heroku 平台。这可能会花费一到两分钟 - Heroku 并不支持 Swift 作为原生语言,它会下载 Swift 二进制文件,安装,编译和安装应用程序[由于意外错误的发生,演讲中并未完全演示成功]。

服务端 Swift 能否用于正式项目? (25:37)

答案是否定的。Foundation 库在 Linux 系统中依旧尚未成熟。如果想要进行网络请求,你无法使用 iOS 和 OS X 系统上提供的 NSURLRequest NSURLSession。你必须直接链接 C 二进制文件,例如 libcurl 库,直接操纵请求。管理 Swift 的多个版本让人伤透了脑筋。Swift 语言每个发布版本都在不断变化(并非开玩笑),但是我觉得 Swift 3 预览版之后可能情况会有所好转(希望在WWDC 或不久之后)。

当然,Swift 仍然是最棒的。服务端 Swift 开发很有意思。看着社区活跃的氛围,我非常激动。此外,我认为 Swift 将逐渐占据一定服务端份额。

如果你想在空闲时间为服务端 Swift 开发做贡献,这里提供了许多具有吸引力的参与方式。我个人推荐 Vapor,Zewo 以及 open Swift ,它们都提供了Slack channels 帮助你参与进来,而且参与的开发者都非常热心。如果你想真正参与进来,那么请前往他们的 Github 项目:你可以前往他们提供的一个 Slack 频道地址,加入到他们的队伍中去。你可以贡献代码,同时也可以建立自己的不同项目(其乐无穷)。

问答时间到 (26:42)

Q:这太酷了。我好奇的是:对于每个请求是否都需要重新执行 main.swift 文件中的代码,还是说如果请求是一致的,会在多个请求之间保持一个状态。

Edward:是的,你可以在多个请求之间保持某个状态。我没有谈论并发性,但你可以看到,这是一个线程,它不像Express那样异步返回东西。我了解了下四个不同框架内部实现并发性的方式:大多数是使用了线程,而 Vapor 使用了 libdispatch(本质还是使用线程)。每当一个新的请求到来,Vapor 应用将产生一个新的线程或新的调度,或一个 GCD(grand central dispatch) 进程。为每个请求执行代码。Zewo 是个特例。它使用了一个非常有意思的方法。程序内部使用了 libnl,引入了 ghost L 协程概念。此外,他们还将 libnl 封装成了一个名为 VeniceX 的 Swift 包,在 Zewo 中你可以使用协程来实现并发,但本质还是线程。

相关资源

About the content

This content has been published here with the express permission of the author.

Edward Jiang

Edward is a Developer Evangelist at Stormpath, and helps others secure their apps by building better user authentication. Previously, he was the second employee at PadMapper, and rebuilt their iOS app in Swift before they were acquired by Zumper for just under $10M. Edward was also the founder of StudentRND CodeDay, a nationwide hackathon to teach students to code. CodeDay reaches over 2,000 students nationwide in over 20 cities each quarter

4 design patterns for a RESTless mobile integration »

close