swift URLSession HTTP响应处理

mccptt67  于 2023-08-02  发布在  Swift
关注(0)|答案(1)|浏览(143)

我有一个文件用于处理对NestJS API的http post请求。我的网站工作得很好,它接受来自API的任何响应。但是在xcode中,我必须硬编码响应。网站可以接受bool响应,但据我所知,xcode只接受json。
有没有人能纠正我,告诉我,如果你能让xcode接受来自API的任何响应。谢谢你,谢谢

HttpPOST.swift

import Foundation
func apiCall(url: String, body: Dictionary<String, AnyHashable>, completion: @escaping (Response) -> Void){
    
    guard let url = URL(string: "http://192.168.1.71:3000/user/login")else{
        return
    }
    
    var request = URLRequest(url: url)
    // method, body, headers
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    let body: [String: AnyHashable] = body
    request.httpBody = try? JSONSerialization.data(withJSONObject: body, options: .fragmentsAllowed)
    
    // make rqs
    let task = URLSession.shared.dataTask(with: request){ data, response, error in
        guard let data = data,error == nil else {
            return
        }
        
        do {
            let response = try JSONDecoder().decode(Response.self, from: data)
            completion(response)
        }
        
        catch {
            print(error)
        }
        
    }
    
    task.resume()
}

struct Response: Codable {
    var usernameError: String?;
    var passwordError: String?;
    var logOk: Bool?;
    var token: String?;
}

字符串

响应示例

Response(usernameError: Optional("enteruname"), passwordError: Optional("enterpasswd"), logOk: Optional(false), token: nil)

42fyovps

42fyovps1#

使返回类型为泛型,以便能够返回任何Decodable类型,甚至是单个Bool值。
这是你的代码的现代版本,它throws任何可能的错误

func apiCall<T: Decodable>(urlString: String = "http://192.168.1.71:3000/user/login", body: [String:AnyHashable]) async throws -> T {
    
    guard let url = URL(string: urlString) else { throw URLError(.badURL) }
    
    var request = URLRequest(url: url)
    // method, body, headers
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.httpBody = try JSONSerialization.data(withJSONObject: body)
    
    // make rqs
    let (data, _) = try await URLSession.shared.data(for: request)
    return try JSONDecoder().decode(T.self, from: data)
}

字符串
并加以利用

Task {
    do {
        let result : Response = try await apiCall(body: ["Foo":"Bar"])
    } catch {
        print(error)
    }
}

编辑:

为了区分successfailure,将Response声明为具有关联值的枚举。成功时返回令牌,失败时返回错误消息

enum Response: Decodable {
    case success(String), failure((String,String))
    
    private enum CodingKeys: String, CodingKey { case usernameError, passwordError, logOk, token}
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let ok = try container.decode(Bool.self, forKey: .logOk)
        if ok {
            self = .success(try container.decode(String.self, forKey: .token))
        } else {
            
            let usernameError = try container.decodeIfPresent(String.self, forKey: .usernameError) ?? ""
            let passwordError = try container.decodeIfPresent(String.self, forKey: .passwordError) ?? ""
            self = .failure((usernameError, passwordError))
        }
    }
}


并将调用代码更改为

Task {
    do {
        let result : Response = try await apiCall(body: ["Foo":"Bar"])
        switch result {
            case .success(let token): print(token)
            case .failure(let usernameError, let passwordError): print(usernameError, passwordError)
        }
    } catch {
        print(error)
    }
}

相关问题