使用 Swift 5 发出 HTTP GET 请求

问题描述

我显然遗漏了一些非常基本的/天真的/等等,但在我的一生中,我无法弄清楚如何发出简单的 GET 请求。

我正在尝试使用 Swift 5 发出 HTTP GET 请求。我查看了以下帖子/文章onetwo,但我无法获取 print()陈述以显示任何内容。当我使用断点进行调试时,会跳过 URLSession.shared.dataTask 部分中的整个部分。
我正在查看以下代码(来自上面的第一个链接):

func HTTP_Request() {
    let url = URL(string: "http://www.stackoverflow.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 命令行项目中运行它。

如果我能在这方面得到任何帮助,我将不胜感激,谢谢。

解决方法

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

RunLoop.main.run()

sleep(UINT32_MAX)

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

let semphare = DispatchSemaphore(value: 0)

func HTTP_Request() {
    let url = URL(string: "http://www.stackoverflow.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.stackoverflow.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.stackoverflow.com")! // note,error in
            defer {
                DispatchQueue.main.async {
                    completion()
                }
            }
    
            guard
                error == nil,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. 如果是 Playground,你必须设置 needsIndefiniteExecution

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

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

,

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

let url = URL(string: "https://google.com")
    let task = URLSession.shared.dataTask(with: ((url ?? URL(string: "https://google.com"))!)) { [self] (data,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()
}