swift (六) http

18 阅读2分钟

http编程

import Foundation

func getRequest(urlStr: String) {
    guard let url = URL(string: urlStr) else {
        print("URL 无效")
        return
    }
    let task = URLSession.shared.dataTask(with: url) { data, response, error in
        if let error = error {
            print("请求失败:\(error.localizedDescription)")
            return
        }
        guard let data = data else {
            print("无返回数据")
            return
        }
        // 解析数据
        if let str = String(data: data, encoding: .utf8) {
            print("返回内容:\(str)")
        }
    }
    task.resume()
}

// 调用
getRequest(urlStr: "https://httpbin.org/get")
// POST JSON
func postJson(urlStr: String, params: [String: Any]) {
    guard let url = URL(string: urlStr) else { return }
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")

    do {
        request.httpBody = try JSONSerialization.data(withJSONObject: params)
    } catch {
        print("参数转JSON失败:\(error)")
        return
    }

    URLSession.shared.dataTask(with: request) { data, _, error in
        if let error = error {
            print(error)
            return
        }
        guard let data = data else { return }
        print(String(data: data, encoding: .utf8) ?? "")
    }.resume()
}

// 调用
postJson(urlStr: "https://httpbin.org/post", params: ["name": "Swift", "age": 20])

async await

import Foundation

// 自定义错误
enum NetworkError: Error {
    case invalidURL
    case noData
    case requestFailed
}

// GET 异步请求
func asyncGet(urlStr: String) async throws -> Data {
    guard let url = URL(string: urlStr) else { throw NetworkError.invalidURL }
    let (data, response) = try await URLSession.shared.data(from: url)

    guard let httpResp = response as? HTTPURLResponse,
          (200...299).contains(httpResp.statusCode) else {
        throw NetworkError.requestFailed
    }
    return data
}

// POST JSON 异步请求
func asyncPost(urlStr: String, params: [String: Any]) async throws -> Data {
    guard let url = URL(string: urlStr) else { throw NetworkError.invalidURL }
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.httpBody = try JSONSerialization.data(withJSONObject: params)

    let (data, response) = try await URLSession.shared.data(for: request)
    guard let httpResp = response as? HTTPURLResponse,
          (200...299).contains(httpResp.statusCode) else {
        throw NetworkError.requestFailed
    }
    return data
}

切换回来主线程

func testAsyncHttp() {
    Task {
        do {
            let data = try await asyncGet(urlStr: "https://httpbin.org/get")
            let result = String(data: data, encoding: .utf8) ?? ""

            // 切主线程更新 UI
            await MainActor.run {
                print("主线程收到数据:\(result.prefix(200))")
                // label.text = result
            }
        } catch {
            await MainActor.run {
                print("请求异常:\(error)")
            }
        }
    }
}

testAsyncHttp()

结合 Codable 做统一解析,一套方法支持所有接口。

import Foundation

enum NetError: Error {
    case invalidURL, noData, statusError
}

// 通用请求工具
final class HttpTool {
    static let shared = HttpTool()
    private init() {}

    /// 通用 GET 请求,自动解析 Model
    func get<T: Codable>(urlStr: String) async throws -> T {
        guard let url = URL(string: urlStr) else { throw NetError.invalidURL }
        let (data, resp) = try await URLSession.shared.data(from: url)
        try checkResponse(resp)
        return try JSONDecoder().decode(T.self, from: data)
    }

    /// 通用 POST JSON 请求
    func post<T: Codable>(urlStr: String, params: [String: Any]) async throws -> T {
        guard let url = URL(string: urlStr) else { throw NetError.invalidURL }
        var req = URLRequest(url: url)
        req.httpMethod = "POST"
        req.setValue("application/json", forHTTPHeaderField: "Content-Type")
        req.httpBody = try JSONSerialization.data(withJSONObject: params)

        let (data, resp) = try await URLSession.shared.data(for: req)
        try checkResponse(resp)
        return try JSONDecoder().decode(T.self, from: data)
    }

    // 校验状态码
    private func checkResponse(_ response: URLResponse) throws {
        guard let httpResp = response as? HTTPURLResponse,
              (200...299).contains(httpResp.statusCode) else {
            throw NetError.statusError
        }
    }
}

// ------------------- 使用示例 -------------------
// 1. 定义数据模型
struct HttpBinModel: Codable {
    let url: String
    let origin: String
}

// 2. 发起请求
func requestModel() {
    Task {
        do {
            let model: HttpBinModel = try await HttpTool.shared.get(urlStr: "https://httpbin.org/get")
            await MainActor.run {
                print("解析结果:\(model.url)")
            }
        } catch {
            print("请求/解析失败:\(error)")
        }
    }
}

requestModel()