服务器端Swift:制作机盖(2/6)

上周,我谈到了我如何发现Swift是服务器端开发的绝佳选择。 本周,我将讨论平台的选择。

顶篷在这里可用。

首先,我想重申我的承诺:只要我的Patreon目标得以实现,就可以将Canopy的客户端和服务器端开源。 我想成为一名全职的开源开发人员,Canopy的货币化是我想要到达那里的一种方式,但是如果我不需要,我宁愿将自己的工作交给社区。

需要的顶篷:

  • 具有SSL功能的Web服务器
  • 与苹果的推送通知服务进行通信的APNs引擎
  • 数据库
  • 通用密码功能

我考虑的选项是:

  1. 完善
  2. Kitura
  3. 重新发明轮子

我选择了完美。 让我们谈一谈。

重新发明轮子

网络服务器并不复杂。 但是边缘情况 。 我并不反对重新发明轮子,通常这很有趣,而且在此过程中您经常学到很多东西。 为我自己动手的最好理由是,当出现问题时,您会知道代码,因此更容易解决问题。 如果黑匣子修复出现问题,您自己可能会很难。

不过,我从未真正考虑过Canopy的这种选择:我想构建一个强大而可靠的解决方案; 制作自己的Web服务器肯定会把我咬死,而且肯定会在生产过程中最糟糕的时间发生。

因此,我的决定将归结为:

  1. 堆栈的成熟度
  2. 博客中的大量材料,平台文档以及现有stackoverflow答案的相对有用性

成熟的堆栈是希望已经稳定并且相对没有错误的堆栈。

堆栈在GitHub上具有良好的开发人员影响力,这是我遇到问题时可以希望得到帮助的堆栈。

关于堆栈的大量博客文章等表明其他人已经进行了测试,该堆栈可能在现实世界中使用。 大量的问题和至关重要的答案 ,StackOverflow表示我会在开发过程中以及生产中遇到问题时找到帮助。

完善

Perfect是从Java移植到Swift的成熟解决方案,已经存在了很多年。 我在网上发现了很多信息

蒸气是纯Swift解决方案。 这直接关系到更轻松的构建系统寿命。 任何对依赖图有经验的人都熟悉错误的位是“本机”扩展这一事实。 该工具必须与C库或非该语言的其他库集成的地方。 正如我上周所说,相对于例如,这在Swift中是相当轻松的。 红宝石。 我仍然无法在Mojave上构建一堆gem,因为它们需要libxml或其他任何东西,并且Mojave移到了各种C标头所在的位置。

但是蒸气是相当新的并且处于助焊剂状态。

但是我喜欢Vapor是一个真正充满活力的开源项目,积极而热情地维护着。

它还具有一个美丽且非常周到的API。

Kitura

Kitura得到了IBM强大力量的支持,他们自己使用它,人们为此而付出了很多报酬。 自Swift发行以来,IBM一直以非常鼓舞人心的方式致力于Swift。

但是我并不热衷于可用的API,而Kitura大约和Vapor一样成熟。

为什么我选择完美

所有解决方案的性能都非常好。 因此,这并不是主要问题(尽管Perfect赢得了链接比较)。

Perfect的API足够惯用并且对我来说很有意义,尽管它们不是很“敏捷”,并且在许多地方似乎都没有考虑。 总体而言,该平台的成熟性使我胜过了。 由于这是我在服务器上的第一个Swift项目,因此我希望在较低级别上尽可能避免麻烦,并且它拥有最多的第三方文档,这些文档在开发过程中对我有帮助。

结果怎么样? 不完美

善良

这是一个可靠的系统,我遇到的问题很少(Perfect本身)。 我发现很容易找出如何使用它并找到所需的功能。 表现不错。 开箱即用,它支持我需要的所有内容(SSL,APN,WebSocket,密码学等)。

我也喜欢没有黑匣子。 您编写main.swift ,控制服务器的入口点并运行它,然后执行为您创建的二进制SwiftPM。 蒸气可以相同,但是他们的教程将引导您到他们的自动执行模型,在该模型中您可以编写YAML文件(ugh)并执行其二进制文件以启动服务器。

魔术越少,调试问题就越容易。 干净利落。

它们还提供了整个示例组织,使入门变得更加简单。 我需要新工具中的这些东西。 例子就是我发现的最简单的例子。 提供生成的API参考的工具至少不会被我试用。

API不好

该API并不是很好,但可以使用

小东西在磨碎。 该API通常使用[UIint8]而不是奇怪的Data 。 我认为这可能是因为Perfect在开源后不久就为Swift发行了,而那时的Foundation大部分都没有实现。 但是在字节数组和Data之间进行转换是一个持续的麻烦,因为Codable以及所有内容都需要Data

这些API具有将输入的数据解码为Decodable便利,但是它们需要Codable而不是Decodable 。 这似乎(如果可能的话,我可能看不出实际原因,请原谅我)就像对细节的关注不足,因为它是传入数据,我只需要对其进行解码即可。 将其标记为Codable意味着Swift必须为我的类型生成解码以及编码机制,从而膨胀最终的二进制大小(也许优化程序将其删除了)。 但是对我来说更重要的是,这意味着我对API感到困惑,我一直四处张望,以防误解,将API Decodable标记为用户可以了解其用途:它是用于接收,而不是用于发送。

一个简单的完美服务器可能是:

因此,一旦构建( swift build )并运行( .build/debug/server_name ),您可以转到http:// localhost / foo,它将运行上述路由。 请注意,您必须以root身份为端口80(默认)运行服务器,并且Perfect足够先进以提供API,因此您可以在执行后降级到另一个用户,这肯定是在生产中进行的。 最好以最小的权限创建一个新的Linux用户。

如您所见,Perfect具有一些特殊之处,例如HTTP响应代码的枚举。 如果您完全知道整数代码,则可以使用整数代码,但是显然不应该这样做,但是您可以选择并灵活地执行这两种操作。

写坏路线很容易

如上例所示,您通过在HTTPResponse对象上调用函数进行响应(上述闭包中的第二个参数,Perfect的示例从不对处理程序使用内联闭包,我也没有,也不应:将路由放入自己的文件中) 。

我经常遇到我(偶然地)没有完成请求的路径,如果我们要最大程度地使用该语言,我们将使Swift本身拒绝编译未“完成”请求的代码。 由于我们生活在异步世界中,因此我编写了自己的Route扩展,要求您返回Promise 。 值得注意的是,这就是Vapor所做的。

因此,不完成任何请求而不是隐藏的生产错误成为了编译错误。 理想情况下,Perfect可以做到这一点。

APNs困境

Perfect提供的APNs(推送通知)系统尚未投入生产。 我很高兴他们提供了一个,所以我使用了它。 但是很快我发现了问题。 与维护人员进行一些来回交流,虽然最初很棒,因为他们解决了我的问题,但经过更多测试之后,结果却停滞了票。 因此,我研究了修复Perfect实现的方法,但最终意识到这将是一项艰巨的工作,并且我知道足以编写自己的代码以满足自己的特定和有限的需求。

我知道这不是开源应该如何工作的方法,但是我确实做了尝试,并且研究他们的代码和Apple文档的过程使我意识到,编写我自己的东西来满足自己的需求将具有更大的价值。实施。 有时就是这样。

就像我上次说的那样,Swift允许轻松地与c库集成,因此我跳槽使用libcurl,因为它具有APNs要求的成熟的HTTPS2支持。 自己写书很有趣,花了大约两天的时间,

不幸的是,这留下了我只在生产中发现的错误。 我没有正确关闭连接,最终由于打开了太多文件描述符,内核终止了我的服务器。 那时我没有配置systemd来控制我的服务器,因此它没有重新启动。 我现在正在使用systemd,并且也修复了该错误。

最初,我本人与APN进行交流的想法让我感到害怕,毕竟,这似乎是一个可怕的不透明系统,只能由“超级工程师”之类的人来解决,但是编写我自己的图层的过程使我请记住,通常那种恐吓的感觉只是因为您没有尝试过。 阅读文档并尝试一下。 苹果的系统实际上非常简单,要启动,我现在对HTTP2有了很多了解,顺便说一下,这是一件很整洁的事情。

编写自己的文件会导致我在Swift上遇到的第一个构建问题,因为我需要比提供的系统更新的libcurl。 正如我在上面所说的,这对Vapor来说是一个加号,它是纯粹的Swift,一个完全由其控制的较小的依赖图是一个加号。 但是最终这很容易解决,因为SwiftPM在该领域设计得很好。

URLSession失败

不是Perfect的错,但我对URLSession的某些极端情况下的行为未实现感到痛苦。 特别是对我来说,当我使用Apple验证应用内购买收据时,他们的服务器会执行某些操作,导致URLSession需要在请求内进行查找(不确定是否会发生TBH),但是在Linux Foundation中,这是致命的未实现。

幸运的是,Perfect提供了CURLRequest (libcurl的一个更“快速”的包装器),它易于使用且运行良好,因此我在需要在路由中进行其他联网的任何地方都切换到了该CURLRequest 。 该类的API令人讨厌,TBH,但我再次赞扬Perfect,因为我在需要它们时可以提供解决方案。

最小层的价值

Perfect具有最小的“魔力”,因此,我知道我可以使用DispatchQueueNSFileManager ,按我认为合适的方式操作文件系统,集成任何我喜欢的数据库系统等。

您可以选择更多涉及的系统,例如。 Rails,但是要使用这种系统花很多年才能确定您是否可以做一些简单的事情,例如写入文件,并且这样做不会破坏某件事,或者由于某种原因而不是一种“好的做法”。

每个人都有自己的想法,但我对此表示赞赏。 我知道用Perfect执行的每条路由只是并发队列上的DispatchQueue.async 。 一切都使用了我在Apple平台上多年的开发中就已经知道的机械。 而且,我认为很重要的一点是,使用经过良好测试,设计良好的系统,这些系统由Apple多年生产。

我认为下次我选择Vapor时,社区真的很活跃,其代码质量很高。

云提供商,Linux上的Swift,开发过程和部署。