在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称:swift-server/async-http-client开源软件地址:https://github.com/swift-server/async-http-client开源编程语言:Swift 98.6%开源软件介绍:AsyncHTTPClientThis package provides simple HTTP Client library built on top of SwiftNIO. This library provides the following:
NOTE: You will need Xcode 13.2 or Swift 5.5.2 to try out Getting StartedAdding the dependencyAdd the following entry in your .package(url: "https://github.com/swift-server/async-http-client.git", from: "1.9.0") and .target(name: "MyApp", dependencies: [.product(name: "AsyncHTTPClient", package: "async-http-client")]), Request-Response APIThe code snippet below illustrates how to make a simple GET request to a remote server. Please note that the example will spawn a new If your application does not use SwiftNIO yet, it is acceptable to use import AsyncHTTPClient
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
/// MARK: - Using Swift Concurrency
let request = HTTPClientRequest(url: "https://apple.com/")
let response = try await httpClient.execute(request, timeout: .seconds(30))
print("HTTP head", response)
if response.status == .ok {
let body = try await response.body.collect(upTo: 1024 * 1024) // 1 MB
// handle body
} else {
// handle remote error
}
/// MARK: - Using SwiftNIO EventLoopFuture
httpClient.get(url: "https://apple.com/").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
}
}
} You should always shut down async/await examplesExamples for the async/await API can be found in the Usage guideThe default HTTP Method is Using Swift Concurrencyimport AsyncHTTPClient
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
do {
var request = HTTPClientRequest(url: "https://apple.com/")
request.method = .POST
request.headers.add(name: "User-Agent", value: "Swift HTTPClient")
request.body = .bytes(ByteBuffer(string: "some data"))
let response = try await httpClient.execute(request, timeout: .seconds(30))
if response.status == .ok {
// handle response
} else {
// handle remote error
}
} catch {
// handle error
}
// it's important to shutdown the httpClient after all requests are done, even if one failed
try await httpClient.shutdown() Using SwiftNIO EventLoopFutureimport AsyncHTTPClient
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
defer {
try? httpClient.syncShutdown()
}
var request = try HTTPClient.Request(url: "https://apple.com/", 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
}
}
} Redirects followingEnable follow-redirects behavior using the client configuration: let httpClient = HTTPClient(eventLoopGroupProvider: .createNew,
configuration: HTTPClient.Configuration(followRedirects: true)) TimeoutsTimeouts (connect and read) can also be set using the client configuration: let timeout = HTTPClient.Configuration.Timeout(connect: .seconds(1), read: .seconds(1))
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew,
configuration: HTTPClient.Configuration(timeout: timeout)) or on a per-request basis: httpClient.execute(request: request, deadline: .now() + .milliseconds(1)) StreamingWhen dealing with larger amount of data, it's critical to stream the response body instead of aggregating in-memory. The following example demonstrates how to count the number of bytes in a streaming response body: Using Swift Concurrencylet httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
do {
let request = HTTPClientRequest(url: "https://apple.com/")
let response = try await httpClient.execute(request, timeout: .seconds(30))
print("HTTP head", response)
// if defined, the content-length headers announces the size of the body
let expectedBytes = response.headers.first(name: "content-length").flatMap(Int.init)
var receivedBytes = 0
// asynchronously iterates over all body fragments
// this loop will automatically propagate backpressure correctly
for try await buffer in response.body {
// for this example, we are just interested in the size of the fragment
receivedBytes += buffer.readableBytes
if let expectedBytes = expectedBytes {
// if the body size is known, we calculate a progress indicator
let progress = Double(receivedBytes) / Double(expectedBytes)
print("progress: \(Int(progress * 100))%")
}
}
print("did receive \(receivedBytes) bytes")
} catch {
print("request failed:", error)
}
// it is important to shutdown the httpClient after all requests are done, even if one failed
try await httpClient.shutdown() Using HTTPClientResponseDelegate and SwiftNIO EventLoopFutureimport NIOCore
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 response 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://apple.com/")
let delegate = CountingDelegate()
httpClient.execute(request: request, delegate: delegate).futureResult.whenSuccess { count in
print(count)
} File downloadsBased on the let client = HTTPClient(eventLoopGroupProvider: .createNew)
let request = try HTTPClient.Request(
url: "https://swift.org/builds/development/ubuntu1804/latest-build.yml"
)
let delegate = try FileDownloadDelegate(path: "/tmp/latest-build.yml", reportProgress: {
if let totalBytes = $0.totalBytes {
print("Total bytes count: \(totalBytes)")
}
print("Downloaded \($0.receivedBytes) bytes so far")
})
client.execute(request: request, delegate: delegate).futureResult
.whenSuccess { progress in
if let totalBytes = progress.totalBytes {
print("Final total bytes count: \(totalBytes)")
}
print("Downloaded finished with \(progress.receivedBytes) bytes downloaded")
} Unix Domain Socket PathsConnecting to servers bound to socket paths is easy: let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
httpClient.execute(
.GET,
socketPath: "/tmp/myServer.socket",
urlPath: "/path/to/resource"
).whenComplete (...) Connecting over TLS to a unix domain socket path is possible as well: let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
httpClient.execute(
.POST,
secureSocketPath: "/tmp/myServer.socket",
urlPath: "/path/to/resource",
body: .string("hello")
).whenComplete (...) Direct URLs can easily be constructed to be executed in other scenarios: let socketPathBasedURL = URL(
httpURLWithSocketPath: "/tmp/myServer.socket",
uri: "/path/to/resource"
)
let secureSocketPathBasedURL = URL(
httpsURLWithSocketPath: "/tmp/myServer.socket",
uri: "/path/to/resource"
) Disabling HTTP/2The exclusive use of HTTP/1 is possible by setting var configuration = HTTPClient.Configuration()
configuration.httpVersion = .http1Only
let client = HTTPClient(
eventLoopGroupProvider: .createNew,
configuration: configuration
) SecurityPlease have a look at SECURITY.md for AsyncHTTPClient's security process. |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论