这个包提供了一个基于 SwiftNIO 构建的简单 HTTP 客户端库。
这个库提供以下功能:
注意: 您需要 Xcode 10.2 或 Swift 5.0 才能试用 AsyncHTTPClient
。
在您的 Package.swift
中添加以下条目以开始使用 HTTPClient
.package(url: "https://github.com/swift-server/async-http-client.git", from: "1.0.0")
并将 AsyncHTTPClient
依赖添加到您的 target
.target(name: "MyApp", dependencies: ["AsyncHTTPClient"]),
以下代码片段说明了如何向远程服务器发出简单的 GET 请求。
请注意,该示例将产生一个新的 EventLoopGroup
,它将创建新的线程,这是一个非常耗费资源的操作。在实际应用中使用 SwiftNIO 的其他部分(例如 Web 服务器)时,请优先使用 eventLoopGroupProvider: .shared(myExistingEventLoopGroup)
来共享 AsyncHTTPClient 使用的 EventLoopGroup
与应用程序的其他部分。
如果您的应用程序尚未使用 SwiftNIO,则可以接受使用 eventLoopGroupProvider: .createNew
,但请确保在整个应用程序中共享返回的 HTTPClient
实例。不要创建大量的具有 eventLoopGroupProvider: .createNew
的 HTTPClient
实例,这非常浪费并且可能耗尽程序的资源。
import AsyncHTTPClient
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
httpClient.get(url: "https://swiftlang.cn").whenComplete { result in
switch result {
case .failure(let error):
// process error
case .success(let response):
if response.status == .ok {
// handle response
} else {
// handle remote error
}
}
}
您应该始终关闭使用 try httpClient.syncShutdown()
创建的 HTTPClient
实例。请注意,您必须在 HTTP 客户端的所有请求完成之前调用 httpClient.syncShutdown
,否则正在进行的请求很可能会因为其网络连接中断而失败。
大多数常见的 HTTP 方法都已开箱即用。如果您需要更好地控制方法,或者想要添加标头或正文,请使用 HTTPRequest
结构体
import AsyncHTTPClient
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
defer {
try? httpClient.syncShutdown()
}
var request = try HTTPClient.Request(url: "https://swiftlang.cn", method: .POST)
request.headers.add(name: "User-Agent", value: "Swift HTTPClient")
request.body = .string("some-body")
httpClient.execute(request: request).whenComplete { result in
switch result {
case .failure(let error):
// process error
case .success(let response):
if response.status == .ok {
// handle response
} else {
// handle remote error
}
}
}
使用客户端配置启用 follow-redirects 行为
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew,
configuration: HTTPClient.Configuration(followRedirects: true))
超时(连接和读取)也可以使用客户端配置进行设置
let timeout = HTTPClient.Timeout(connect: .seconds(1), read: .seconds(1))
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew,
configuration: HTTPClient.Configuration(timeout: timeout))
或者在每个请求的基础上进行设置
httpClient.execute(request: request, deadline: .now() + .milliseconds(1))
在处理大量数据时,至关重要的是对响应正文进行流式传输,而不是在内存中聚合。使用委托协议完成处理响应流。以下示例演示了如何计算流式响应正文中的字节数
import NIO
import NIOHTTP1
class CountingDelegate: HTTPClientResponseDelegate {
typealias Response = Int
var count = 0
func didSendRequestHead(task: HTTPClient.Task<Response>, _ head: HTTPRequestHead) {
// this is executed right after request head was sent, called once
}
func didSendRequestPart(task: HTTPClient.Task<Response>, _ part: IOData) {
// this is executed when request body part is sent, could be called zero or more times
}
func didSendRequest(task: HTTPClient.Task<Response>) {
// this is executed when request is fully sent, called once
}
func didReceiveHead(task: HTTPClient.Task<Response>, _ head: HTTPResponseHead) -> EventLoopFuture<Void> {
// this is executed when we receive HTTP Reponse head part of the request (it contains response code and headers), called once
// in case backpressure is needed, all reads will be paused until returned future is resolved
return task.eventLoop.makeSucceededFuture(())
}
func didReceiveBodyPart(task: HTTPClient.Task<Response>, _ buffer: ByteBuffer) -> EventLoopFuture<Void> {
// this is executed when we receive parts of the response body, could be called zero or more times
count += buffer.readableBytes
// in case backpressure is needed, all reads will be paused until returned future is resolved
return task.eventLoop.makeSucceededFuture(())
}
func didFinishRequest(task: HTTPClient.Task<Response>) throws -> Int {
// this is called when the request is fully read, called once
// this is where you return a result or throw any errors you require to propagate to the client
return count
}
func didReceiveError(task: HTTPClient.Task<Response>, _ error: Error) {
// this is called when we receive any network-related error, called once
}
}
let request = try HTTPClient.Request(url: "https://swiftlang.cn")
let delegate = CountingDelegate()
httpClient.execute(request: request, delegate: delegate).futureResult.whenSuccess { count in
print(count)
}