Swift中的HTTP(十七) 头脑风暴

5,761 阅读6分钟

HTTP简介

HTTP基础结构

HTTP请求体

HTTP 加载请求

HTTP 模拟测试

HTTP 链式加载器

HTTP 动态修改请求

HTTP 请求选项

HTTP 重置

HTTP 取消

HTTP 限流

HTTP 重试

HTTP 基础鉴权

HTTP 自动鉴权设置

HTTP 自动鉴权

HTTP 复合加载器

HTTP 头脑风暴

HTTP 总结

我原计划在不同的加载器上发布更多的帖子,你可以使用这个架构构建,但是为了“完成”这个系列,我决定放弃一个帖子每个加载器,而是强调要点 其中一些。

OpenID

我们已经了解了如何实现通过 OAuth 2 流授权请求的加载程序,但在其之上存在一个抽象,称为 OpenID。 使用 OAuth 加载程序,我们需要指定登录 url、刷新令牌的 url 等内容。 OpenID 允许身份提供者通过发送包含所有这些 url(以及协议的其他特性)的清单来抽象化这一点。

如果我们想自己实现 OpenID,我们需要在我们的状态机中有一个初步状态来首先获取这个清单,然后将其用作后续状态逻辑的基础。 或者,我们可以将 OpenID 的现有实现(例如官方实现)包装在自定义 HTTPLoader 子类中,并允许该库执行复杂的逻辑。 在这种情况下,我们的 HTTPLoader 子类将充当库提供的 API 与 HTTP 加载程序链所需的 API 之间的适配器。

缓存

从概念上讲,缓存加载器应该相对简单易懂。 当一个请求进入这个加载器时,它会检查请求(可能还有一个 HTTPRequestOption 来指示是否允许缓存)并查看它是否与任何已保存的响应(在内存中、磁盘上等)相匹配。 如果存在这样的响应,则加载程序返回该响应,而不是将请求进一步发送到链中。

如果响应不存在,它会继续执行典型的请求,但也会插入另一个完成处理程序,以便它可以捕获响应,并且(如果满足正确的条件)将其持久化以用于未来的请求。

重复备份

重复备份类似于缓存,因为当一个请求进来时,加载器会查看它是否与一个已经在进行中的请求相似。 如果是,则新请求被搁置,当原始请求得到响应时,该响应被复制到第二个请求。

重定向

有几种方法可以处理重定向请求。

默认情况下,URLSession 将遵循重定向,除非您特别覆盖 URLSessionTaskDelegate 上的 willPerformHTTPRedirection 委托方法。 因此,您可以这样做,然后有条件地允许根据您创建的特定 HTTPRequestOption 对请求进行重定向。

或者,您可以无条件地拒绝 URLSession 级别的重定向,然后有一个单独的 RedirectionFollowingLoader 接收传入请求,复制它们,并将重复项发送到链中。 当副本返回时,加载器检查响应并查看它是否是重定向响应。 如果是,那么它会为重定向构造一个新请求,并将其发回。

一旦加载程序返回非重定向响应,它就会使用该响应作为对原始请求的响应并将其发回。 您将需要一些逻辑来检测重定向循环并打破它们,但这里的关键思想是发送请求的副本,以便您有机会在决定如何处理之前检查响应。

证书固定

原则上,证书固定应该看起来像任何其他 HTTPLoader:一个请求进来,在它被发送到下一个请求之前,目标服务器的证书根据作为 HTTPRequestOption 附加到请求的证书进行验证。

实际上,这有点困难,因为证书仅在 URLSessionLoader 中协商到远程服务器的连接时可用。 因此,此处的操作过程是不使用单独的 CertificatePinningLoader,而是向 HTTPRequest 提供 CertificateValidator 值,如果加载程序需要执行某些证书验证(类似于 Alamofire 的 ServerTrustEvaluating 协议),则可以使用该值。

然后我们的 URLSessionLoader 需要更新为使用委托,并实现委托方法来处理 URLAuthenticationChallenge,然后在收到 .serverTrust 质询时为请求查询该选项。

点对点

点对点加载器很有趣,因为它源于这样一种认识,即 HTTPLoader 的合同没有说明响应来自哪个设备。 我们已经看到了加载程序的示例,这些加载程序将返回虚假响应(用于模拟)或重用响应(缓存和重复数据删除)。 P2P 加载器可以决定将请求发送到另一台设备,并允许该设备提供响应。

这可以通过多种技术来实现,从 MultipeerConnectivity 到蓝牙或直接套接字连接。 这里的可能性非常大。

敏锐的观察者还会意识到我们早先创建的 URLSessionLoader 属于此类。 这是一个加载程序,可以将生成请求的责任“卸载”到另一个设备。 它恰好是一个同时也是 HTTP 服务器的设备,但我们的加载堆栈并不需要直接知道这一点。

流式响应

该框架不能很好地工作的一个领域是流式响应。 这很明显:我们已经围绕这样的期望构建了一切,即离散且有限的请求具有离散且有限的响应。 流媒体打破了这种期望。 我们可以在上传中做一个流式主体,因为发送该流的过程是发送我们单个离散请求的一部分。

我们可以处理一些类型的流媒体主体,例如文件下载。 对于这些,我们想提供一个 OutputStream(或类似的)来表示“把你得到的任何字节放回这里”; 默认情况下,这可能是内存中数据值的流。 这将允许我们将响应直接流式传输到文件,而不是通过内存中的数据值。

对于实时视频流,我们可以提供一个 OutputStream 将数据通过管道传输到 AVSession 中。 但是,为了使这项工作有效,我们将明确放弃“单一请求,单一响应”的一些语义。 我们还需要非常小心我们如何实现请求复制(例如重定向加载程序需要)。

结论

我们可以用这个框架做很多事情。 有些事情有些复杂,需要解决/使用系统 API 的特定实现细节(例如证书固定、流式响应等)。 总的来说,这种将网络建模为“发送请求并最终获得响应”的方法使我们能够构建极其灵活、可组合和可定制的网络堆栈。

在下一篇(也可能是最后一篇)博文中,我们将缩小范围以查看我们创建的框架的高级概述,并了解它如何适应其他 Swift 技术。