原文来自静雅斋,转载请注明出处。

作为一门新兴的现代化语言,Swift 可以说是苹果在开发语言上的一次集大成之作,吸收了很多语言的优点。而且苹果还期望 Swift 能在服务端开发上能发挥作用。更加诱人的是,作为一种编译型语言,有着 C++ 一般的性能,并且相比 Golang、Java 来说使用 ARC 管理内存避免了 GC 导致进程停顿。可以说 Swift 就是程序员梦寐以求的语言。

Swift 目前在后端开发的缺点

虽然 Swift 本身有很多优点,但是在后端开发上依旧任重道远,比如有以下问题:

  1. 目前只适配了 Ubuntu 下的二进制包,没有 RHEL 等其他 Linux 下的二进制包

  2. 缺乏非 Mac 系统下的 IDE 开发,这个目前看起来好像只能指望 Jetbrains 了

  3. 没有其他语言那么完善的生态系统

  4. 缺乏的文档,比如包管理系统的语法文档,必须自行查看源代码

  5. 没有交叉编译链,不能在 Mac 上面编译出 Linux 可用的二进制文件

  6. 缺乏好用的单元测试

但是这些问题目前都有方法克服,比如使用 Docker 作为承载 Swift 程序的容器,而使用 Mac 来开发 Swift 程序也不是很大的问题,因为大多数的后端开发都是用 Mac 开发的。

Docker 的作用

笔者个人认为 Docker 解决的最大的问题就是开发环境和生产环境的矛盾,对于开发人员来说,追新永远是必备素质,而测试和运维不会希望环境变更导致的问题,比如线上服务器跑的是 CentOS,而 Swift 则是必须在 Ubuntu 上运行,但是 Docker 的出现就能解决这个问题。笔者认为最适合运行在 Docker 中的就是像 Web 这样的服务,Nginx 和数据库之类的就不适合放在 Docker 中,因为它们是有状态的,而且 Docker 这样的快速消亡快速创建的模式也不适合数据库这样对数据有着严格要求的应用。当然,Kubernetes 目前推出的 petset 就很适合数据库这样的有状态的应用。

Perfect 框架

Perfect 框架是 Swift 开发的 Web 应用服务器,它支持包括 Redis、sqlite、Postgresql、MysqL、MongoDB、FileMaker 这样的数据库,并且能以 fastcgi 或者 Web 服务器的形式提供服务。更加美妙的是,还有高质量的中文文档。

HelloWorld

Perfect 提供了基础模板工程,可以使用以下命令下载

> git clone git@github.com:PerfectlySoft/PerfectTemplate.git

然后安装依赖

> swift package fetch

然后就能编译运行了

# 以 Debug 方式编译
> swift build
# 以 Release 方式编译
> swift build -c release

分析 HelloWorld

HelloWorld 工程依赖了 Perfect-HTTPServer 模块,然后其中有两个源文件,arguments.swiftmain.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

一般来说,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 指令复制当前目录下的文件。

Swift 后端开发的更多相关文章

  1. ios – 无法识别的选择器发送到实例NSTimer Swift

    解决方法让updateTime成为一个类方法.如果它是在一个纯粹的Swift类中,你需要在@objc前面说明该方法的声明,如:

  2. ios – 类型推断(自动类型检测)如何在swift中工作?

    LLVM如何检测变量是一个字符串?

  3. ios – Swift可选项:语言问题,还是做错了什么?

    应该有可选的类型;type是但是,如果我这样做,它的工作原理:它似乎是基本的替代,但我可能会遗漏一些语言的细微差别.谁能对此有所了解?之后就像暧昧一样,更多,这是我的解决方案:这适用于所有非对象Swift对象,包括Swift字符串,数字等.感谢Viktor提醒我String不是Swift中的对象.如果您知道值的类型,您可以替换任何?使用适当的可选类型,如String?

  4. ios – 覆盖Swift中的超类委托

    我正在开发一个包含两个UIViews的Swift(v1.2)项目.MyView和MyViewSubclass.MyView有一个委托,我想在MyViewSubclass中覆盖它作为一个子协议,类似于UITableViews有一个UITableViewDelegate,它也符合超级uiscrollviewdelegate.我的第一个想法是覆盖超类属性,但这会导致编译器错误,因为子类不能覆盖具有不同类

  5. ios – 我可以在swift中将字符串转换为代码块吗?

    有没有办法将字符串转换为代码块?

  6. ios – Swift:方法重载只在返回类型上有所不同

    我一直在看Swift类,其中定义了两种方法,它们的返回类型不同.我不习惯使用允许这种语言的语言,所以我去寻找描述它如何在Swift中工作的文档.我在任何地方都找不到任何东西.我本来期望在Swift书中有关于它的整个部分.这记录在哪里?

  7. ios – 字符串资源Xcode swift

    我是iOS开发和Swift语言的新功能.而且我尝试制作简单的iOS应用程序,我需要在应用程序中使用一些字符串资源.当然,我可以将这个字符串放在我的*.swift文件中作为常量,但我认为这是一个坏的方法.我该怎么做?

  8. ios – 如何使用新的Apple Swift语言发布JSON

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  9. ios – Swift元组到可选分配

    我在Swift编写一些代码来学习语言.这是我的基础课:问题在最后一行:编译器说“不能表达元组转换to”我明白问题是self.status和self.message是可选的,parseResponse不返回可选.我如何告诉它做必要的分配和转换,以获取数据到实例变量?

  10. ios – 使用未申报的“AppDelegate”Swift

    您可能会看到AppDelegate代码here,但是我没有修改任何由xCode自动生成的内容.我创建了一个具有this设置的单一视图应用程序.解决方法很有可能当您创建项目时,您还创建了一个“{ProjectName}Tests”目标.问题是AppDelegate没有在“{ProjectName}Tests”目标中分配成员资格.选择AppDelegate.swift,然后在右侧检查器中单击文件检查器,然后确保在“目标成员资格”中,您的项目和测试目标复选标记都设置为ON.清洁,重建.

随机推荐

  1. Swift UITextField,UITextView,UISegmentedControl,UISwitch

    下面我们通过一个demo来简单的实现下这些控件的功能.首先,我们拖将这几个控件拖到storyboard,并关联上相应的属性和动作.如图:关联上属性和动作后,看看实现的代码:

  2. swift UISlider,UIStepper

    我们用两个label来显示slider和stepper的值.再用张图片来显示改变stepper值的效果.首先,这三个控件需要全局变量声明如下然后,我们对所有的控件做个简单的布局:最后,当slider的值改变时,我们用一个label来显示值的变化,同样,用另一个label来显示stepper值的变化,并改变图片的大小:实现效果如下:

  3. preferredFontForTextStyle字体设置之更改

    即:

  4. Swift没有异常处理,遇到功能性错误怎么办?

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  5. 字典实战和UIKit初探

    ios中数组和字典的应用Applicationschedule类别子项类别名称优先级数据包contactsentertainment接触UIKit学习用Swift调用CocoaTouchimportUIKitletcolors=[]varbackView=UIView(frame:CGRectMake(0.0,0.0,320.0,CGFloat(colors.count*50)))backView

  6. swift语言IOS8开发战记21 Core Data2

    上一话中我们简单地介绍了一些coredata的基本知识,这一话我们通过编程来实现coredata的使用。还记得我们在coredata中定义的那个Model么,上面这段代码会加载这个Model。定义完方法之后,我们对coredata的准备都已经完成了。最后强调一点,coredata并不是数据库,它只是一个框架,协助我们进行数据库操作,它并不关心我们把数据存到哪里。

  7. swift语言IOS8开发战记22 Core Data3

    上一话我们定义了与coredata有关的变量和方法,做足了准备工作,这一话我们来试试能不能成功。首先打开上一话中生成的Info类,在其中引用头文件的地方添加一个@objc,不然后面会报错,我也不知道为什么。

  8. swift实战小程序1天气预报

    在有一定swift基础的情况下,让我们来做一些小程序练练手,今天来试试做一个简单地天气预报。然后在btnpressed方法中依旧增加loadWeather方法.在loadWeather方法中加上信息的显示语句:运行一下看看效果,如图:虽然显示出来了,但是我们的text是可编辑状态的,在storyboard中勾选Editable,再次运行:大功告成,而且现在每次单击按钮,就会重新请求天气情况,大家也来试试吧。

  9. 【iOS学习01】swift ? and !  的学习

    如果不初始化就会报错。

  10. swift语言IOS8开发战记23 Core Data4

    接着我们需要把我们的Rest类变成一个被coredata管理的类,点开Rest类,作如下修改:关键字@NSManaged的作用是与实体中对应的属性通信,BinaryData对应的类型是NSData,CoreData没有布尔属性,只能用0和1来区分。进行如下操作,输入类名:建立好之后因为我们之前写的代码有些地方并不适用于coredata,所以编译器会报错,现在来一一解决。

返回
顶部