// // NetworkManager.swift // iOSFirst // // Created by 孙宇峰 on 2023/2/22. // import Foundation import Moya import Alamofire import HandyJSON import RxSwift import SwiftyJSON /// 超时时长 private var requestTimeOut:Double = 30 ///endpointClosure public let myEndpointClosure = { (target: TargetType) -> Endpoint in ///这里的endpointClosure和网上其他实现有些不太一样。 ///主要是为了解决URL带有?无法请求正确的链接地址的bug let url = target.baseURL.absoluteString + target.path var endpoint = Endpoint( url: url, sampleResponseClosure: { .networkResponse(200, target.sampleData) }, method: target.method, task: target.task, httpHeaderFields: target.headers ) switch target { default: requestTimeOut = 30//设置默认的超时时长 return endpoint } } public let requestClosure = { (endpoint: Endpoint, done: MoyaProvider.RequestResultClosure) in do { var request = try endpoint.urlRequest() //设置请求时长 request.timeoutInterval = requestTimeOut // 打印请求参数 if let requestData = request.httpBody { log.info("\(request.url!)"+"\n"+"\(request.httpMethod ?? "")"+"发送参数"+"\(String(data: request.httpBody!, encoding: String.Encoding.utf8) ?? "")") }else{ log.info("\(request.url!)"+"\(String(describing: request.httpMethod))") } if let header = request.allHTTPHeaderFields { log.info("请求头内容\(header)") } done(.success(request)) } catch { done(.failure(MoyaError.underlying(error, nil))) } } /// NetworkActivityPlugin插件用来监听网络请求 public let networkPlugin = NetworkActivityPlugin.init { (changeType, targetType) in log.info("networkPlugin \(changeType)") //targetType 是当前请求的基本信息 switch(changeType){ case .began: log.info("开始请求网络") case .ended: log.info("结束") } } // https://github.com/Moya/Moya/blob/master/docs/Providers.md 参数使用说明 //stubClosure 用来延时发送网络请求 final class TdwMoyaPlugin: PluginType { public func prepare(_ request: URLRequest, target: TargetType) -> URLRequest { var request = request request.addValue("token值", forHTTPHeaderField: "token名字") return request } } /* Moya默认有4个插件分别为: AccessTokenPlugin 管理AccessToken的插件 CredentialsPlugin 管理认证的插件 NetworkActivityPlugin 管理网络状态的插件 NetworkLoggerPlugin 管理网络log的插件 */ // 插件,实现pluginType可以实现在网络请求前转菊花,请求完成结束转菊花,或者写日志等功能 struct NetworkPlugin: PluginType { let userDefault=UserDefaults.standard /// Called to modify a request before sending.(可进行数据加密等) func prepare(_ request: URLRequest, target: TargetType) -> URLRequest { var mRequest = request let key = "XINGHUOLIAOYUAN7" // let jsonString = AESEncryptor.aes_encrypt(request.httpBody!.toHexString(),aes_key: key) //TODO AES加密相关 let jsonString = aesEncryptData(request.httpBody,key.data(using: .utf8)) // let jsonString = AESEncryptor.aes_encrypt(request.httpBody!.toHexString(),aes_key: key) //TODO AES加密相关 // let jsonString = aesEncryptString(String(data: request.httpBody!, encoding: String.Encoding.utf8) ?? "",key) mRequest.httpBody = jsonString?.toHexString().data(using: .utf8) print(""" #############↓网络请求参数↓################# \(target.baseURL)\(target.path) \(jsonString?.toHexString() ?? "无参数") #############↑网络请求参数↑################# """) let userinfo = NSKeyedUnarchiver.unarchiveObject(with: userDefault.object(forKey: "userinfo") as! Data ) as! LoginUserInfo if(userDefault.bool(forKey: "isLogin")){ let bool = userDefault.bool(forKey: "isLogin") log.info("prepare\(bool)") let cc = userinfo.cloudcode == nil ? "" : userinfo.cloudcode ?? "" let id = userinfo.userid == nil ? "" : String(userinfo.userid ?? -1) let tv = (userinfo.token_value == nil ? "" : userinfo.token_value) ?? "" let key = "\(cc)_\(id)_p_phone_t" mRequest.addValue(key, forHTTPHeaderField: "Token_Key") mRequest.addValue(tv, forHTTPHeaderField: "Token_Value") } if let header = mRequest.allHTTPHeaderFields { log.info("请求头内容\(header)") } return mRequest } /// Called immediately before a request is sent over the network (or stubbed).(可进行网络等待,loading等) func willSend(_ request: RequestType, target: TargetType) { // guard let target = target as? AccountService else { return } // let jsonData = try? JSONSerialization.data(withJSONObject: target.parameters, options: .prettyPrinted) // let jsonString = String(data: jsonData ?? Data(), encoding: .utf8) // print(""" // #############↓网络请求参数↓################# // \(target.baseURL)\(target.path) // \(jsonString ?? "无参数") // #############↑网络请求参数↑################# // """) } /// Called after a response has been received, but before the MoyaProvider has invoked its completion handler.(loading结束等) func didReceive(_ result: Result, target: TargetType) { } /// Called to modify a result before completion.(可进行数据解密等) func process(_ result: Result, target: TargetType) -> Result { return result } } let accountProvider = MoyaProvider(endpointClosure: myEndpointClosure, requestClosure: requestClosure, plugins: [networkPlugin], trackInflights: false) public class NetworkManaer{ /// 使用Moya的请求封装 /// /// - Parameters: /// - target: 请求API,TargetType里的枚举值 /// - success: 成功的回调 /// - error: 连接服务器成功但是数据获取失败 /// - failure: 连接服务器失败 /// public class func request(_ target: T, success: @escaping((U) -> Void), failure: ((Int?, String) ->Void)?) { let provider = MoyaProvider( endpointClosure: myEndpointClosure, requestClosure: requestClosure, plugins: [networkPlugin,NetworkPlugin.init()], trackInflights: false // networkLoggerPlugin ) provider.request(target) { result in switch result { case let .success(response): // let json = try? response.mapString() // let responseObject = try? response.mapJSON() // JhLog( responseObject ?? "" ); do { // *********** 这里可以统一处理错误码,弹出提示信息 *********** let resObject = try? response.mapJSON() log.info("网络请求到的数据是:\(resObject)") let responseObject = JSON(resObject ?? "") let code = responseObject["code"].intValue let msg = String(describing: responseObject["msg"]) switch (code) { case 0 : let dictionary=responseObject["obj"].dictionaryObject let responseData=U.deserialize(from: dictionary) log.info(responseData?.toJSONString()) // 数据返回正确 success(responseData!) case 2: let userDefault=UserDefaults.standard userDefault.setValue(false, forKey: "isLogin") // 请重新登录 failure!(code,msg) alertLogin(msg) default: // 其他错误 failureHandle(failure: failure, stateCode: code, message: msg) } } case let .failure(error): let statusCode = error.response?.statusCode ?? 1000 let message = "请求出错,错误码:" + String(statusCode) log.error(message) failureHandle(failure: failure, stateCode: statusCode, message: error.errorDescription ?? message) } } // 错误处理 - 弹出错误信息 func failureHandle(failure: ((Int?, String) ->Void)? , stateCode: Int?, message: String) { // Alert.show(type: .error, text: message) //弹出错误信息 failure?(stateCode ,message) } // 登录弹窗 - 弹出是否需要登录的窗口 func alertLogin(_ title: String?) { // TODO: 跳转到登录页的操作: } } // MARK: - 打印日志 // static let networkLoggerPlugin = NetworkLoggerPlugin(verbose: true, cURL: true, requestDataFormatter: { data -> String in // return String(data: data, encoding: .utf8) ?? "" // }) { data -> (Data) in // do { // let dataAsJSON = try JSONSerialization.jsonObject(with: data) // let prettyData = try JSONSerialization.data(withJSONObject: dataAsJSON, options: .prettyPrinted) // return prettyData // } catch { // return data // } // } }