0

以下是我的APIManager代码,我在所有应用程序中都使用它。但有时,guard 语句在功能上失败connectToServer,这意味着除了我的记录之外,这里的事情甚至在插入statusCodeDBHTTPURLResponse之后200...299也是如此statusCode200...299。我不知道会发生什么。

我认为这种行为的原因来自ServerURL,因为我使用的开发服务器的 IP 地址http://00.000.0.000/没有安全性。一旦我将它移至域,因为https://XXX.XXXXXXXXXX.XXXXX/它工作正常。你能帮我弄清楚这个吗?

它还支持异步调用吗?

import UIKit

struct APIResponse : Decodable {
    let status : Bool
    let message : String
    let extra: String?
}

internal let BASE_URL = "http://00.000.0.00/app/v0_1/api/" // Example server URL

enum APIPath: String {
    
    case registration = "registration"
    case login = "login"
    case getProfile = "get_profile"
    
    func directURL() -> URL? {
        let urlPath = BASE_URL + self.rawValue
        return URL(string: urlPath)
    }
    
    func extendedURL(using parameters: [String: Any]) -> URL? {
        let extendedPath = parameters.map { $0.key + "=" + "\($0.value)" }.joined(separator: "&")
        let urlPath = BASE_URL + self.rawValue + "?" + extendedPath
        return URL(string: urlPath)
     }
    
}

enum APIMethod: String {
    case get = "GET"
    case put = "PUT"
    case post = "POST"
    case patch = "PATCH"
    case delete = "DELETE"
}

enum APIHeaders {
    case user
    case app
    
    var authorization: [String:String] {
        let acceptLanguage = UserDefaults.standard.value(forKey: UDKeys.appleLanguage) as? String ?? ""
        if self == .user {
            let token = UserDefaults.standard.value(forKey: UDKeys.userToken) as? String ?? ""
            return ["Content-Type": "application/json", "Accept": "application/json", "Accept-Language": acceptLanguage, "Token" : token]
        }
        return ["Content-Type": "application/json", "Accept": "application/json", "Accept-Language": acceptLanguage]
    }
}

struct APIRequest {
    
    var url: URL?
    var method: String
    var parameters: Data?
    var headers: [String:String]
    
    init(path: APIPath, method: APIMethod, headers: APIHeaders) {
        self.url = path.directURL()
        self.method = method.rawValue
        self.headers = headers.authorization
    }
    
    init(path: APIPath, parameters: [String: Any], method: APIMethod, headers: APIHeaders) {
        self.url = path.extendedURL(using: parameters)
        self.method = method.rawValue
        self.headers = headers.authorization
    }
    
    init(path: APIPath, method: APIMethod, body: [String:Any], headers: APIHeaders) {
        self.url = path.directURL()
        self.method = method.rawValue
        self.parameters = try? JSONSerialization.data(withJSONObject: body, options: .sortedKeys)
        self.headers = headers.authorization
    }
    
    init<Encode: Encodable>(path: APIPath, method: APIMethod, body: Encode, headers: APIHeaders) {
        self.url = path.directURL()
        self.method = method.rawValue
        self.parameters = try? JSONEncoder().encode(body)
        self.headers = headers.authorization
    }
    
}

struct APIError: Error {
    let reason: String
    let code: String?
    init(reason: String, code: String? = nil) {
        self.reason = reason
        self.code = code
    }
}


struct APIDispatcher {
    
    static let instance = APIDispatcher()
    private init() {}
        
    func dispatch<Decode: Decodable>(request: APIRequest, response: Decode.Type, result: @escaping (Result<Decode, APIError>) -> ()) {
        DispatchQueue(label: "queue", attributes: .concurrent).async {
            self.connectToServer(with: request) { (resultant) in
                switch resultant {
                case .success(let data):
                    do {
                        let decoded = try JSONDecoder().decode(response, from: data)
                        DispatchQueue.main.async {
                            result(.success(decoded))
                        }
                    } catch let decodedError {
                        print("[Decoded Error]: ", decodedError)
                        do {
                            let apiResponse = try JSONDecoder().decode(APIResponse.self, from: data)
                            let apiError = APIError(reason: apiResponse.message, code: apiResponse.extra)
                            DispatchQueue.main.async {
                                result(.failure(apiError))
                            }
                        } catch {
                            let apiError = APIError(reason: decodedError.localizedDescription)
                            DispatchQueue.main.async {
                                result(.failure(apiError))
                            }
                        }
                    }
                case .failure(let error):
                    DispatchQueue.main.async {
                        result(.failure(error))
                    }
                }
            }
        }
    }
    
    func dispatch(request: APIRequest, result: @escaping (Result<Dictionary<String,Any>, APIError>) -> ()) {
        DispatchQueue(label: "queue", attributes: .concurrent).async {
            self.connectToServer(with: request) { (resultant) in
                switch resultant {
                case .success(let data):
                    do {
                        let serialized = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! Dictionary<String,Any>
                        DispatchQueue.main.async {
                            result(.success(serialized))
                        }
                    } catch {
                        let error = APIError(reason: error.localizedDescription)
                        DispatchQueue.main.async {
                            result(.failure(error))
                        }
                    }
                case .failure(let error):
                    DispatchQueue.main.async {
                        result(.failure(error))
                    }
                }
            }
        }
    }
    
    private func connectToServer(with request: APIRequest, result: @escaping (Result<Data, APIError>) -> ()) {
        
        guard let url = request.url else {
            let error = APIError(reason: "Invalid URL")
            result(.failure(error))
            return
        }
                
        var urlRequest = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: 30)
        urlRequest.httpMethod = request.method
        urlRequest.httpBody = request.parameters
        urlRequest.allHTTPHeaderFields = request.headers
        
        print(urlRequest)
        
        let urlSessionConfiguration = URLSessionConfiguration.default
        urlSessionConfiguration.waitsForConnectivity = false
        urlSessionConfiguration.timeoutIntervalForRequest = 30
        urlSessionConfiguration.timeoutIntervalForResource = 60
        
        let urlSession = URLSession(configuration: urlSessionConfiguration)
        urlSession.dataTask(with: urlRequest) { (data, response, error) in
            if let error = error {
                let error = APIError(reason: error.localizedDescription)
                result(.failure(error))
                return
            }
            guard let httpResponse = response as? HTTPURLResponse,
                  (200...299).contains(httpResponse.statusCode) else {
                let error = APIError(reason: "Server Error")
                result(.failure(error))
                return
            }
            if let data = data {
                result(.success(data))
            }
        }.resume()
        
    }
    
}

注意:BASE_URL 和 APIResponse 可能因项目而异。

我用它作为


func login() {
        self.startLoading()
        let body = ["mobile_number": phoneNumberTF.text!, "password" : passwordTF.text!, "uuid" : UIDevice.current.identifierForVendor!.uuidString]
        let apiRequest = APIRequest(path: .login, method: .post, body: body, headers: .app)
        APIDispatcher.instance.dispatch(request: apiRequest) { result in
            self.stopLoading()
            switch result {
            case .success(let response):
                break
            case .failure(let error):
                break
            }
        }
    }


编辑:我的错我statsCode现在完全颠倒了我修改它。

4

0 回答 0