使用 Swift 发出 HTTP GET 请求 5

Making HTTP GET request with Swift 5

我显然错过了一些非常 fundamental/naïve/etc 的东西,但对于我来说,我无法弄清楚如何发出简单的 GET 请求。

我正在尝试使用 Swift 5 发出 HTTP GET 请求。我查看了这些 posts/articles:one, two,但我无法获得 print() 语句来显示任何内容。当我使用断点进行调试时,URLSession.shared.dataTask 部分中的整个部分被跳过。
我正在查看以下代码(来自上面的第一个 link):

func HTTP_Request() {
    let url = URL(string: "http://www.whosebug.com")!

    let task = URLSession.shared.dataTask(with: url) {(data: Data?, response: URLResponse?, error: Error?) in
        guard let data = data else { return }
        print(String(data: data, encoding: .utf8)!)
    }
    task.resume()
}

HTTP_Request()

我是 运行 通过 XCode 创建的 MacOS 命令行项目。

我将不胜感激任何对此的帮助,谢谢。

这对我有用很多次我建议你摘录以备将来使用!

let url = URL(string: "https://google.com")
    let task = URLSession.shared.dataTask(with: ((url ?? URL(string: "https://google.com"))!)) { [self] (data, response, error) in
        
        do {
            let jsonResponse = try JSONSerialization.jsonObject(with: data!, options: [])
            print(jsonResponse)
            guard let newValue = jsonResponse as? [String:Any] else {
                print("invalid format")
                }
            }

        
        catch let error {
            print("Error: \(error)")
        }
        
    task.resume()
}

确保在退出进程之前打印响应,您可以尝试追加

RunLoop.main.run()

sleep(UINT32_MAX)

最后确保主线程不会退出。如果要打印响应并立即退出进程,建议使用 DispatchSemaphore:

let semphare = DispatchSemaphore(value: 0)

func HTTP_Request() {
    let url = URL(string: "http://www.whosebug.com")!

    let task = URLSession.shared.dataTask(with: url) {(data: Data?, response: URLResponse?, error: Error?) in
        guard let data = data else { return }
        print(String(data: data, encoding: .utf8)!)
        semphare.signal()
    }
    task.resume()
}

HTTP_Request()

_ = semphare.wait(timeout: .distantFuture)

现在,如果出现错误,您将默默地失败。所以添加一些错误日志记录,例如,

func httpRequest() {
    let url = URL(string: "https://www.whosebug.com")! // note, https, not http

    let task = URLSession.shared.dataTask(with: url) { data, response, error in
        guard
            error == nil,
            let data = data,
            let string = String(data: data, encoding: .utf8)
        else {
            print(error ?? "Unknown error")
            return
        }

        print(string)
    }
    task.resume()
}

这至少应该给你一些问题的指示。

其他一些注意事项:

  1. 如果是命令行应用程序,您必须认识到应用程序可能会在此异步网络请求完成之前退出。人们通常会启动一个 RunLoop,用 run(mode:before:) 循环直到网络请求完成,正如 run documentation.

    中所建议的那样

    例如,您可以为该例程提供一个完成处理程序,该处理程序将在完成时在主线程上调用。然后你可以使用它:

    func httpRequest(completion: @escaping () -> Void) {
        let url = URL(string: "https://www.whosebug.com")! // note, https, not http
    
        let task = URLSession.shared.dataTask(with: url) { data, response, error in
            defer {
                DispatchQueue.main.async {
                    completion()
                }
            }
    
            guard
                error == nil,
                let data = data,
                let string = String(data: data, encoding: .utf8)
            else {
                print(error ?? "Unknown error")
                return
            }
    
            print(string)
        }
        task.resume()
    }
    
    var finished = false
    
    httpRequest {
        finished = true
    }
    
    while !finished {
        RunLoop.current.run(mode: .default, before: .distantFuture)
    }
    
  2. 在标准的 macOS 应用程序中,您必须在“应用程序沙盒”功能中启用传出(客户端)连接。

  3. 如果是游乐场,则必须设置needsIndefiniteExecution

  4. 默认情况下,macOS 和 iOS 应用禁用 http 请求,除非您在 Info.plist 中启用“允许任意加载”。这不适用于命令线应用程序,但如果您尝试在标准 macOS/iOS 应用程序中执行此操作,您应该意识到这一点。

    在这种情况下,您应该只使用 https 并完全避免这种考虑。