Swift3 如何使用swift 3进行同步url请求

Swift3 如何使用swift 3进行同步url请求,swift3,alamofire,vapor,kitura,Swift3,Alamofire,Vapor,Kitura,我知道以前有人问过这个问题,我同意大多数的回答,他们认为最好遵循Swift 3中与URLSession异步的请求方式。我有以下场景,其中不能使用异步请求 有了Swift 3和在服务器上运行Swift的能力,我有以下问题 服务器接收来自客户端的请求 要处理请求,服务器必须发送url请求并等待响应到达 一旦收到响应,处理它并回复给客户机 问题出现在第2步,其中URLSession使我们能够仅启动异步数据任务。大多数(如果不是全部的话)服务器端swift web框架不支持异步响应。当一个请求到达服务器

我知道以前有人问过这个问题,我同意大多数的回答,他们认为最好遵循Swift 3中与URLSession异步的请求方式。我有以下场景,其中不能使用异步请求

有了Swift 3和在服务器上运行Swift的能力,我有以下问题

  • 服务器接收来自客户端的请求
  • 要处理请求,服务器必须发送url请求并等待响应到达
  • 一旦收到响应,处理它并回复给客户机
  • 问题出现在第2步,其中URLSession使我们能够仅启动异步数据任务。大多数(如果不是全部的话)服务器端swift 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框架的经验,这就是我面临的问题所在。我认为所有其他swift web框架中都存在类似的问题。

    在Vapor中,您可以使用Droplet的客户端来进行同步请求

    let res = try drop.client.get("https://httpbin.org")
    print(res)
    
    此外,您可以使用
    门户
    类使异步任务同步

    let res = try Portal.open { portal in
        asyncClient.get("https://httpbin.org") { res in
            portal.close(with: res)
        }
    }
    

    您的三步问题可以通过使用完成处理程序来解决,即回调处理程序和la 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://www.example.com
    ,等待响应,然后将结果发送回我的应用程序的客户端


    链接到相关API:

    从未想过这个简单的解决方案。我的印象是,您应该在同一线程中使用“res”,而不是在完成块中使用。当你说“非最佳实践”时,你能解释一下原因吗?@zirinisp I没有包括正确的错误处理或可选的展开(
    如果let data=data
    )。对于来自
    dataTask
    的错误和来自
    res.send
    的可能错误(可能会重新引用第二个错误),您应该在生产代码中包含错误处理。我认为“非最佳实践”是从块发送响应。只要这不是一个问题,那么这就是解决方案(我的头脑被卡住了,正在寻找复杂的替代方案)。非常感谢。看来Vapor已经看透了。我更喜欢第二种方法,因为它对任何场景都是通用的(不绑定到特定的框架)