美文网首页swift专题
Alamofire 二次封装

Alamofire 二次封装

作者: 西风那个吹呀吹 | 来源:发表于2022-09-05 22:07 被阅读0次

须导入 Alamofire HandyJSON

1. 基类模型

struct CoscoBaseModel: HandyJSON {
    /// 错误码
    var code: Int?
    var status: Int?
    /// 数据
    var data: Any?
    /// 提示信息
    var message: String?
    /// 成功 true  失败 false
    var success: Bool = false
}

2. token 模型

struct AccessToken: HandyJSON, Identifiable, Codable {
    var id = UUID()
    var access_token: String?
    var token_type: String?
    var expires_in: Double?
    var storageTimestamp: TimeInterval = Date().timeIntervalSince1970
}

3. 拦截器

class CoscoRequestInterceptor: RequestInterceptor {
    func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
        let request = sign(request: urlRequest)
        completion(.success(request))
    }
    
    func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) {
        
        guard let response = request.task?.response as? HTTPURLResponse, (response.statusCode == 401)  else {
            /// 这个请求没有因为 401 token 过期
            /// 则进行原始请求,不重试
            return completion(.doNotRetryWithError(error))
        }
        
        // 确保只重试一次,否则会无限重试下去
        guard request.retryCount == 0 else {
            return completion(.doNotRetry)
        }

        HttpClient.getAccessToken { token in
            // 缓存token
            let json = try? JSONEncoder().encode(token)
            UserDefaults.standard.set(json, forKey: "coscoToken")
            // 1秒后进行重试
            completion(.retryWithDelay(1))
        } errorCompletion: { msg in
            // 刷新token失败放弃重试
            completion(.doNotRetryWithError(error))
        }
    }
    
    // header 添加 token
    private func sign(request: URLRequest) -> URLRequest {
        guard let urlString = request.url?.absoluteString else {
            return request
        }
        if urlString == Api.accessTokenUrl() {
            return request
        }
        var retRequest = request
        if let model = UserDefaults.standard.value(forKey: "coscoToken") {
            let token = try? JSONDecoder().decode(AccessToken.self, from: model as! Data)
            retRequest.setValue(token?.access_token ?? ""), forHTTPHeaderField: "Authorization")
        }
        return retRequest
    }
}

4. 调用类和方法

class HttpClient {
    class func get(_ url: String,  params: [String : Any]? = nil, encoding: ParameterEncoding = URLEncoding.default) {
        
        AF.request(url, method: .get, parameters: params, encoding: encoding, headers: nil, interceptor: CoscoRequestInterceptor(), requestModifier: nil).validate({ request, response, data in
            
            // 401 这种返回,按照请求成功处理。所以不会触发 Retrier. 此处对特定状态码401返回错误
            let statusCode = response.statusCode
            if statusCode != 401 {
                return .success(())
            } else {
                return .failure(AFError.responseValidationFailed(reason: .unacceptableStatusCode(code: 401)))
            }
            
        }).responseString(encoding: .utf8) { response in
            // 用utf8 编码,否则中文会是乱码
            switch response.result {

            case .success(let json):
                guard let baseModel = CoscoBaseModel.deserialize(from: json) else {
                    return print("请求出错~")
                }

                print("数据--:", baseModel)

            case .failure(let error):
                print("错误", error)
            }
        }
    }
    
    // 获取token
    class func getAccessToken(success: @escaping (_ token : AccessToken) -> (), errorCompletion: @escaping (_ msg : String) -> ()) {
        // token 请求地址
        let url = Api.accessTokenUrl()
        let params = 此处为获取token的参数
        let headers: HTTPHeaders = HTTPHeaders(["Content-Type" : "application/x-www-form-urlencoded;charset=UTF-8"])
        
        // 注意:此处是用 URL 编码参数的 POST 请求方式,不同后端开发或许不同的参数方式,具体情况具体对待
        AF.request(url, method: .post, parameters: params, encoder: URLEncodedFormParameterEncoder.default, headers: headers, interceptor: nil, requestModifier: nil).responseJSON { response in
            
            switch response.result {
            case .success(let json):
                guard let tokenModel = AccessToken.deserialize(from: json as? Dictionary) else {
                    return errorCompletion("获取accessToken失败")
                }
                
                success(tokenModel)
                
            case .failure(let error):
                print(error)
                errorCompletion("服务器连接出错啦~")
            }
        }
    }
}

注意:

用了.responseString这个闭包,必须加上参数(encoding: .utf8),否则中文会乱码,没有中文的数据,加不加都无所谓。

PS: 让Swift社区丰富起来吧

相关文章

  • 我常用的一些库和框架

    常用的pod库 swift版本 Alamofire 网络请求。 Moya 基于 Alamofire 二次封装。 T...

  • Moya集锦

    Moya库是对Alamofire库的二次封装封装. 对于Alamofire咱们在这就不做多余赘述了,感兴趣的可以去...

  • Swift Moya网络请求库的学习认识和简单使用

    Moya是Swift中的网络库Alamofire的二次封装,Alamofire本身使用起来是很简单方便的,例子如下...

  • Moya

    导入pod 'Moya',github地址 Moya是对Alamofire的二次封装 代码演示 协议TargetT...

  • Alamofire 二次封装

    须导入 Alamofire HandyJSON 1. 基类模型 2. token 模型 3. 拦截器 4. 调用类...

  • Alamofire的简单封装

    Alamofire的简单二次封装。这里数据解析使用swiftyJSON 如果headers没有特殊设置,可以在请求...

  • swift 网络请求之解析模型

    一.基于 Alamofire 和 HandyJSON 框架,二次封装网络请求和网络检测。 a.网络检测文件 b. ...

  • swift 封装网络请求(Alamofire)

    对Alamofire进行封装,模块化处理。 一、cocoapods导入Alamofire 参照Alamofire在...

  • Alamofire的二次封装

    Alamofire的二次封装 最近开始在学习Swift,在网络工具的选择中,我选择了AFNetworking的Sw...

  • 12.第三方库

    简介 网络请求-Alamofire Alamofire 是在苹果 URL Loading System 基础上封装...

网友评论

    本文标题:Alamofire 二次封装

    本文链接:https://www.haomeiwen.com/subject/yppbnrtx.html