3

以前に質問があったことは知っていますが、Swift 3 で URLSession を使用してリクエストを非同期にする方法に従う方がよいと主張するほとんどの回答に同意します。非同期リクエストを使用できない次のシナリオがあります。

Swift 3 とサーバー上で迅速に実行する機能には、次の問題があります。

  1. サーバー クライアントからのリクエストを受け取る
  2. リクエストを処理するには、サーバーは URL リクエストを送信し、レスポンスが到着するのを待つ必要があります。
  3. 応答が到着したら、それを処理してクライアントに返信します

問題はステップ 2 で発生します。ここで、URLSession は、非同期データ タスクのみを開始する機能を提供します。ほとんどの (すべてではないにしても) サーバー側の迅速な Web フレームワークは、非同期応答をサポートしていません。リクエストがサーバーに到着したら、すべてを同期的に実行し、最後にレスポンスを送信する必要があります。

これまでに見つけた唯一の解決策は、DispatchSemaphore を使用することです (最後の例を参照)。それが拡張された環境で機能するかどうかはわかりません。

どんな助けや考えもいただければ幸いです。

extension URLSession {
    func synchronousDataTaskWithURL(_ url: URL) -> (Data?, URLResponse?, Error?) {
        var data: Data?
        var response: URLResponse?
        var error: Error?

        let sem = DispatchSemaphore(value: 0)

        let task = self.dataTask(with: url as URL, completionHandler: {
            data = $0
            response = $1
            error = $2 as Error?
            sem.signal()
        })

        task.resume()

        let result = sem.wait(timeout: DispatchTime.distantFuture)
        switch result {
        case .success:
            return (data, response, error)
        case .timedOut:
            let error = URLSessionError(kind: URLSessionError.ErrorKind.timeout)
            return (data, response, error)

        }
    }
}

私はkitura Webフレームワークの経験しかありませんが、これが問題に直面した場所です。同様の問題は、他のすべての迅速な Web フレームワークにも存在すると思います。

4

2 に答える 2

2

Vapor では、Droplet のクライアントを使用して同期リクエストを作成できます。

let res = try drop.client.get("https://httpbin.org")
print(res)

さらに、このPortalクラスを使用して、非同期タスクを同期させることができます。

let res = try Portal.open { portal in
    asyncClient.get("https://httpbin.org") { res in
        portal.close(with: res)
    }
}
于 2016-10-24T16:50:46.220 に答える
1

この 3 ステップの問題は、完了ハンドラー (つまり、Node.js の慣習によるコールバック ハンドラー) を使用して解決できます。

import Foundation
import Kitura
import HeliumLogger
import LoggerAPI

let session = URLSession(configuration: URLSessionConfiguration.default)

Log.logger = HeliumLogger()

let router = Router()

router.get("/test") { req, res, next in
    let datatask = session.dataTask(with: URL(string: "http://www.example.com")!) { data, urlResponse, error in
        try! res.send(data: data!).end()
    }

    datatask.resume()
}

Kitura.addHTTPServer(onPort: 3000, with: router)
Kitura.run()

これはあなたの問題に対する解決策の簡単なデモであり、決して Swift/Kitura のベスト プラクティスに従っているわけではありません。しかし、完了ハンドラーを使用すると、Kitura アプリで HTTP 呼び出しを行って でリソースをフェッチしhttp://www.example.com、応答を待ってから、結果をアプリのクライアントに送り返すことができます。

関連する API へのリンク: https://developer.apple.com/reference/foundation/urlsession/1410330-datatask

于 2016-10-24T21:39:26.580 に答える