Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

swift-server/async-http-client

This package provides an HTTP Client library built on top of SwiftNIO.

This library provides the following:

  • First class support for Swift Concurrency
  • Asynchronous and non-blocking request methods
  • Simple follow-redirects (cookie headers are dropped)
  • Streaming body download
  • TLS support
  • Automatic HTTP/2 over HTTPS
  • Cookie parsing (but not storage)

Getting Started

Adding the dependency

Add the following entry in yourPackage.swift to start usingHTTPClient:

.package(url:"https://github.com/swift-server/async-http-client.git", from:"1.9.0")

andAsyncHTTPClient dependency to your target:

.target(name:"MyApp", dependencies:[.product(name:"AsyncHTTPClient",package:"async-http-client")]),

Request-Response API

The code snippet below illustrates how to make a simple GET request to a remote server.

import AsyncHTTPClient/// MARK: - Using Swift Concurrencyletrequest=HTTPClientRequest(url:"https://apple.com/")letresponse=tryawaitHTTPClient.shared.execute(request, timeout:.seconds(30))print("HTTP head", response)if response.status==.ok{letbody=tryawait response.body.collect(upTo:1024*1024) // 1 MB    // handle body}else{    // handle remote error}/// MARK: - Using SwiftNIO EventLoopFutureHTTPClient.shared.get(url:"https://apple.com/").whenComplete{ resultinswitch result{case.failure(let error):        // process error    case.success(let response):if response.status==.ok{            // handle response}else{            // handle remote error}}}

If you create your ownHTTPClient instances, you should shut them down usinghttpClient.shutdown() when you're done using them. Failing to do so will leak resources.Please note that you must not callhttpClient.shutdown before all requests of the HTTP client have finished, or else the in-flight requests will likely fail because their network connections are interrupted.

async/await examples

Examples for the async/await API can be found in theExamples folder in this Repository.

Usage guide

The default HTTP Method isGET. In case you need to have more control over the method, or you want to add headers or body, use theHTTPClientRequest struct:

Using Swift Concurrency

import AsyncHTTPClientdo{varrequest=HTTPClientRequest(url:"https://apple.com/")    request.method=.POST    request.headers.add(name:"User-Agent", value:"Swift HTTPClient")    request.body=.bytes(ByteBuffer(string:"some data"))letresponse=tryawaitHTTPClient.shared.execute(request, timeout:.seconds(30))if response.status==.ok{        // handle response}else{        // handle remote error}}catch{    // handle error}

Using SwiftNIO EventLoopFuture

import AsyncHTTPClientvarrequest=tryHTTPClient.Request(url:"https://apple.com/", method:.POST)request.headers.add(name:"User-Agent", value:"Swift HTTPClient")request.body=.string("some-body")HTTPClient.shared.execute(request: request).whenComplete{ resultinswitch result{case.failure(let error):        // process error    case.success(let response):if response.status==.ok{            // handle response}else{            // handle remote error}}}

Redirects following

The globally shared instanceHTTPClient.shared follows redirects by default. If you create your ownHTTPClient, you can enable the follow-redirects behavior using the client configuration:

lethttpClient=HTTPClient(eventLoopGroupProvider:.singleton,                            configuration:HTTPClient.Configuration(followRedirects:true))

Timeouts

Timeouts (connect and read) can also be set using the client configuration:

lettimeout=HTTPClient.Configuration.Timeout(connect:.seconds(1), read:.seconds(1))lethttpClient=HTTPClient(eventLoopGroupProvider:.singleton,                            configuration:HTTPClient.Configuration(timeout: timeout))

or on a per-request basis:

httpClient.execute(request: request, deadline:.now()+.milliseconds(1))

Streaming

When 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 Concurrency

do{letrequest=HTTPClientRequest(url:"https://apple.com/")letresponse=tryawaitHTTPClient.shared.execute(request, timeout:.seconds(30))print("HTTP head", response)    // if defined, the content-length headers announces the size of the bodyletexpectedBytes= response.headers.first(name:"content-length").flatMap(Int.init)varreceivedBytes=0    // asynchronously iterates over all body fragments    // this loop will automatically propagate backpressure correctlyfortryawaitbufferin response.body{        // for this example, we are just interested in the size of the fragment        receivedBytes+= buffer.readableBytesiflet expectedBytes= expectedBytes{            // if the body size is known, we calculate a progress indicatorletprogress=Double(receivedBytes)/ Double(expectedBytes)print("progress:\(Int(progress*100))%")}}print("did receive\(receivedBytes) bytes")}catch{print("request failed:", error)}

Using HTTPClientResponseDelegate and SwiftNIO EventLoopFuture

import NIOCoreimport NIOHTTP1classCountingDelegate:HTTPClientResponseDelegate{typealiasResponse=Intvarcount=0func 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 resolvedreturn 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 resolvedreturn 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 clientreturn count}func didReceiveError(task:HTTPClient.Task<Response>, _ error:Error){        // this is called when we receive any network-related error, called once}}letrequest=tryHTTPClient.Request(url:"https://apple.com/")letdelegate=CountingDelegate()HTTPClient.shared.execute(request: request, delegate: delegate).futureResult.whenSuccess{ countinprint(count)}

File downloads

Based on theHTTPClientResponseDelegate example above you can build more complex delegates,the built-inFileDownloadDelegate is one of them. It allows streaming the downloaded dataasynchronously, while reporting the download progress at the same time, like in the followingexample:

letrequest=tryHTTPClient.Request(    url:"https://swift.org/builds/development/ubuntu1804/latest-build.yml")letdelegate=tryFileDownloadDelegate(path:"/tmp/latest-build.yml", reportProgress:{iflet totalBytes= $0.totalBytes{print("Total bytes count:\(totalBytes)")}print("Downloaded\($0.receivedBytes) bytes so far")})HTTPClient.shared.execute(request: request, delegate: delegate).futureResult.whenSuccess{ progressiniflet totalBytes= progress.totalBytes{print("Final total bytes count:\(totalBytes)")}print("Downloaded finished with\(progress.receivedBytes) bytes downloaded")}

Unix Domain Socket Paths

Connecting to servers bound to socket paths is easy:

HTTPClient.shared.execute(.GET,    socketPath:"/tmp/myServer.socket",    urlPath:"/path/to/resource").whenComplete(...)

Connecting over TLS to a unix domain socket path is possible as well:

HTTPClient.shared.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:

letsocketPathBasedURL=URL(    httpURLWithSocketPath:"/tmp/myServer.socket",    uri:"/path/to/resource")letsecureSocketPathBasedURL=URL(    httpsURLWithSocketPath:"/tmp/myServer.socket",    uri:"/path/to/resource")

Disabling HTTP/2

The exclusive use of HTTP/1 is possible by settinghttpVersion to.http1Only onHTTPClient.Configuration:

varconfiguration=HTTPClient.Configuration()configuration.httpVersion=.http1Onlyletclient=HTTPClient(    eventLoopGroupProvider:.singleton,    configuration: configuration)

Security

Please have a look atSECURITY.md for AsyncHTTPClient's security process.

Supported Versions

The most recent versions of AsyncHTTPClient support Swift 6.0 and newer. The minimum Swift version supported by AsyncHTTPClient releases are detailed below:

AsyncHTTPClientMinimum Swift Version
1.0.0 ..< 1.5.05.0
1.5.0 ..< 1.10.05.2
1.10.0 ..< 1.13.05.4
1.13.0 ..< 1.18.05.5.2
1.18.0 ..< 1.20.05.6
1.20.0 ..< 1.21.05.7
1.21.0 ..< 1.26.05.8
1.26.0 ..< 1.27.05.9
1.27.0 ..< 1.30.05.10
1.30.0 ...6.0

[8]ページ先頭

©2009-2025 Movatter.jp