原文來自靜雅齋,轉載請註明出處。html
做爲一門新興的現代化語言,Swift 能夠說是蘋果在開發語言上的一次集大成之做,吸取了不少語言的優勢。並且蘋果還指望 Swift 能在服務端開發上能發揮做用。更加誘人的是,做爲一種編譯型語言,有着 C++ 通常的性能,而且相比 Golang、Java 來講使用 ARC 管理內存避免了 GC 致使進程停頓。能夠說 Swift 就是程序員求之不得的語言。git
雖然 Swift 自己有不少優勢,可是在後端開發上依舊任重道遠,好比有如下問題:程序員
目前只適配了 Ubuntu 下的二進制包,沒有 RHEL 等其餘 Linux 下的二進制包github
缺少非 Mac 系統下的 IDE 開發,這個目前看起來好像只能期望 Jetbrains 了web
沒有其餘語言那麼完善的生態系統docker
缺少的文檔,好比包管理系統的語法文檔,必須自行查看源代碼數據庫
沒有交叉編譯鏈,不能在 Mac 上面編譯出 Linux 可用的二進制文件express
缺少好用的單元測試swift
可是這些問題目前都有方法克服,好比使用 Docker 做爲承載 Swift 程序的容器,而使用 Mac 來開發 Swift 程序也不是很大的問題,由於大多數的後端開發都是用 Mac 開發的。後端
筆者我的認爲 Docker 解決的最大的問題就是開發環境和生產環境的矛盾,對於開發人員來講,追新永遠是必備素質,而測試和運維不會但願環境變動致使的問題,好比線上服務器跑的是 CentOS,而 Swift 則是必須在 Ubuntu 上運行,可是 Docker 的出現就能解決這個問題。筆者認爲最適合運行在 Docker 中的就是像 Web 這樣的服務,Nginx 和數據庫之類的就不適合放在 Docker 中,由於它們是有狀態的,並且 Docker 這樣的快速消亡快速建立的模式也不適合數據庫這樣對數據有着嚴格要求的應用。固然,Kubernetes 目前推出的 petset 就很適合數據庫這樣的有狀態的應用。
Perfect 框架是 Swift 開發的 Web 應用服務器,它支持包括 Redis、SQLite、PostgreSQL、MySQL、MongoDB、FileMaker 這樣的數據庫,而且能以 fastcgi 或者 Web 服務器的形式提供服務。更加美妙的是,還有高質量的中文文檔。
Perfect 提供了基礎模板工程,可使用如下命令下載
> git clone git@github.com:PerfectlySoft/PerfectTemplate.git
而後安裝依賴
> swift package fetch
而後就能編譯運行了
# 以 Debug 方式編譯 > swift build # 以 Release 方式編譯 > swift build -c release
HelloWorld 工程依賴了 Perfect-HTTPServer
模塊,而後其中有兩個源文件,arguments.swift
和 main.swift
main.swift
import PerfectLib import PerfectHTTP import PerfectHTTPServer // Create HTTP server. let server = HTTPServer() // Register your own routes and handlers var routes = Routes() routes.add(method: .get, uri: "/", handler: { request, response in response.setHeader(.contentType, value: "text/html") response.appendBody(string: "<html><title>Hello, world!</title><body>Hello, world!</body></html>") response.completed() } ) // Add the routes to the server. server.addRoutes(routes) // Set a listen port of 8181 server.serverPort = 8181 // Set a document root. // This is optional. If you do not want to serve static content then do not set this. // Setting the document root will automatically add a static file handler for the route /** server.documentRoot = "./webroot" // Gather command line options and further configure the server. // Run the server with --help to see the list of supported arguments. // Command line arguments will supplant any of the values set above. configureServer(server) do { // Launch the HTTP server. try server.start() } catch PerfectError.networkError(let err, let msg) { print("Network error thrown: \(err) \(msg)") }
用過 Node 的 express 框架的朋友是否是感受很熟悉,使用事件循環處理 HTTP 請求,事實上早期的 Perfect 框架用的就是 libev 框架來處理事件循環的 HTTP 請求。
arguments.swift
import PerfectHTTPServer import PerfectLib #if os(Linux) import SwiftGlibc #else import Darwin #endif // Check all command line arguments used to configure the server. // These are all optional and you can remove or add arguments as required. func configureServer(_ server: HTTPServer) { var sslCert: String? var sslKey: String? var args = CommandLine.arguments func argFirst() -> String { guard let frst = args.first else { print("Argument requires value.") exit(-1) } return frst } let validArgs = [ "--sslcert": { args.removeFirst() sslCert = argFirst() }, "--sslkey": { args.removeFirst() sslKey = argFirst() }, "--port": { args.removeFirst() server.serverPort = UInt16(argFirst()) ?? 8181 }, "--address": { args.removeFirst() server.serverAddress = argFirst() }, "--root": { args.removeFirst() server.documentRoot = argFirst() }, "--name": { args.removeFirst() server.serverName = argFirst() }, "--runas": { args.removeFirst() server.runAsUser = argFirst() }, "--help": { print("Usage: \(CommandLine.arguments.first!) [--port listen_port] [--address listen_address] [--name server_name] [--root root_path] [--sslcert cert_path --sslkey key_path] [--runas user_name]") exit(0) }] while args.count > 0 { if let closure = validArgs[args.first!.lowercased()] { closure() } args.removeFirst() } if sslCert != nil || sslKey != nil { if sslCert == nil || sslKey == nil { print("Error: if either --sslcert or --sslkey is provided then both --sslcert and --sslkey must be provided.") exit(-1) } if !File(sslCert!).exists || !File(sslKey!).exists { print("Error: --sslcert or --sslkey file did not exist.") exit(-1) } server.ssl = (sslCert: sslCert!, sslKey: sslKey!) } }
這裏就很簡單了,就是提供參數用於 HTTP 服務器的建立,而這個好處就是能經過參數得到更多功能。
首先使用 swift package init
命令建立工程,通常來講以下
> swift package init --type executable
而後在 Package.swift 中增長依賴,可是 Swift 目前全部的 IDE 都沒有提供對 PackageDescription
模塊的代碼提示,估計是由於這是 Swift 內建模塊。具體內容獲得 Swift 源代碼中能夠找到。
通常來講只要增長以下內容
import PackageDescription let package = Package( name: "XXXX", dependencies: [ .Package(url: "https://github.com/PerfectlySoft/Perfect-HTTPServer.git", majorVersion: 2, minor: 0) ] )
而後建立 main.swift 文件,而且建立 HTTPServer 偵聽端口,就能建立本身的工程了。
通常來講,Docker 目前想要運行 Swift 必須使用 Ubuntu 的鏡像,由於 Swift 的預編譯包只提供 Ubuntu 的壓縮包,可是不少 Docker 鏡像存在不少問題,好比缺乏支持庫,因此須要做出如下修改,下面提供一個樣例
FROM swiftdocker/swift:3.0.1 MAINTAINER ChasonTang <chasontang@gmail.com> RUN apt-get update \ && apt-get install -y uuid-dev libcurl4-openssl-dev libssl-dev \ && git clone https://github.com/PerfectlySoft/PerfectTemplate /usr/src/PerfectTemplate \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* WORKDIR /usr/src/PerfectTemplate RUN swift build -c release CMD .build/release/PerfectTemplate --port 80
Perfect 須要 libcurl 是由於 swift build
獲取依賴的時候是使用 curl 來獲取代碼的,uuid 是由於 Perfect 框架內置函數庫所需,而 openssl 則是 Perfect 依賴的庫所需。這裏使用的是 git clone 的方式獲取工程代碼,可是也能夠經過 COPY 指令複製當前目錄下的文件。