基础
import Moya
import RxSwift
/// 网络请求
class Network {
/// 请求
public static func request(_ requestConfig: RequestConfig) -> Observable<Response> {
return Observable.create { subscribe in
MoyaProvider<RequestConfig>(endpointClosure: requestConfig.endpointClosure,
requestClosure: requestConfig.requestClosure,
stubClosure: requestConfig.stubClosure,
callbackQueue: requestConfig.callbackQueue,
session: requestConfig.session,
plugins: requestConfig.plugins,
trackInflights: requestConfig.trackInflights)
.request(requestConfig, callbackQueue: requestConfig.callbackQueue, progress: requestConfig.progress, completion: { result in
switch result {
case let .success(response):
subscribe.onNext(response)
subscribe.onCompleted()
case let .failure(error):
subscribe.onError(error)
subscribe.onCompleted()
break
}
})
return Disposables.create()
}
}
}
// MARK: - 请求配置扩展
extension Network {
// MARK: 请求配置
class RequestConfig: TargetType {
/// 基础URL
public var baseURL: URL
/// 请求方法
public var method: Moya.Method
/// 请求路径
public var path: String
/// 请求类型,Data/Downlaod/Upload
public var task: Task
/// 请求头
public var headers: [String : String]?
/// 超时时长
public var timeoutInterval: TimeInterval
/// callbackQueue
public var callbackQueue: DispatchQueue?
/// 进度闭包
public var progress: ProgressBlock? = .none
/// 模拟数据
public var sampleData: Data = "".data(using: String.Encoding.utf8)!
public var endpointClosure: MoyaProvider<RequestConfig>.EndpointClosure = MoyaProvider.defaultEndpointMapping
public var requestClosure: MoyaProvider<RequestConfig>.RequestClosure = MoyaProvider<RequestConfig>.defaultRequestMapping
/// 模拟网络请求
public var stubClosure: MoyaProvider<RequestConfig>.StubClosure = MoyaProvider.neverStub
public var session: Session = MoyaProvider<RequestConfig>.defaultAlamofireSession()
/// 插件
public var plugins: [PluginType] = []
public var trackInflights: Bool = false
/// 开始时间,用于请求耗时计算
public var startTime: Date = Date()
/// 初始化
public init(baseURL: URL,
method: Moya.Method,
path: String,
task: Task,
headers: [String : String]?,
timeoutInterval: TimeInterval,
callbackQueue: DispatchQueue? = .main) {
self.baseURL = baseURL
self.method = method
self.path = path
self.task = task
self.headers = headers
self.timeoutInterval = timeoutInterval
self.requestClosure = timeoutClosure()
self.callbackQueue = callbackQueue
}
// 超时中间件
open func timeoutClosure() -> ((_ endpoint: Endpoint, _ closure: MoyaProvider<RequestConfig>.RequestResultClosure) -> Void) {
let timeoutClosure = {(endpoint: Endpoint, closure: MoyaProvider<RequestConfig>.RequestResultClosure) -> Void in
if var urlRequest = try? endpoint.urlRequest() {
urlRequest.timeoutInterval = self.timeoutInterval
closure(.success(urlRequest))
} else {
closure(.failure(MoyaError.requestMapping(endpoint.url)))
}
}
return timeoutClosure
}
}
}
日志插件
// MARK: - 日志扩展
extension Network {
// MARK: 网络日志
class NetworkLogger: PluginType {
public func willSend(_ request: RequestType, target: TargetType) {
let log = self.generateRequestLog(request, target: target)
print(log)
}
public func didReceive(_ result: Result<Moya.Response, MoyaError>, target: TargetType) {
let log = self.generateResponseLog(result, target: target)
print(log)
}
func generateRequestLog(_ request: RequestType, target: TargetType) -> String {
var log = "\n"
log += "===============💜💜💜 Request 💜💜💜 ===============\n"
let url = "\(target.baseURL.absoluteString)\(target.path)"
log += "URL: \(url)\n"
log += "Host: \(target.baseURL.absoluteString)\n"
log += "Path: \(target.path)\n"
log += "Method: \(target.method.rawValue)\n"
log += "Header: \(target.headers ?? [:])\n"
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
log += "Time: \(formatter.string(from: Date()))\n"
log += "Task: \(target.task)\n"
log += "===============💜💜💜 End 💜💜💜===============\n"
return log
}
func generateResponseLog(_ result: Result<Moya.Response, MoyaError>, target: TargetType) -> String {
var log = "\n"
do {
let response = try result.get()
log += "===============💚💚💚 Response 💚💚💚===============\n"
let url = "\(target.baseURL.absoluteString)\(target.path)"
log += "URL: \(url)\n"
if let requestConfig = target as? RequestConfig {
let usedTime = Date().timeIntervalSince1970 - requestConfig.startTime.timeIntervalSince1970
let usedTimeStr = String(format: "%.1f", usedTime)
log += "UsedTime: \(usedTimeStr) s\n"
}
let data = String(data: response.data, encoding: .utf8)
log += data != nil ? "Data: \(data!) \n" : "Data: \n"
log += "===============💚💚💚 End 💚💚💚===============\n"
}catch {
if let error = error as? MoyaError {
log += "===============👿👿👿 Response 👿👿👿===============\n"
let url = "\(target.baseURL.absoluteString)\(target.path)"
log += "URL: \(url)\n"
log += "Error: \(error.errorDescription ?? "") \n"
log += "Code: \(error.errorCode) \n"
if let requestConfig = target as? RequestConfig {
let usedTime = Date().timeIntervalSince1970 - requestConfig.startTime.timeIntervalSince1970
let usedTimeStr = String(format: "%.1f", usedTime)
log += "UsedTime: \(usedTimeStr) s\n"
}
log += "=============== End ===============\n"
}
}
return log
}
}
}
Response解析
import HandyJSON
// MARK: - 扩展解析方法
public extension Observable where Element == Response {
/// 转字典
func mapDictionary() -> Observable<[String : Any]> {
return self.flatMap { element in
return Observable<[String : Any]> .create { observer in
if let dict = try? JSONSerialization.jsonObject(with: element.data, options: .mutableContainers) as? [String: Any] {
observer.onNext(dict)
}else {
observer.onError(MoyaError.jsonMapping(element))
}
observer.onCompleted()
return Disposables.create()
}
}
}
/// 转模型
func mapModel<T: HandyJSON>(_ type: T.Type) -> Observable<T> {
return self.flatMap { element in
return Observable<T>.create { observer in
if let jsonString = String(data: element.data, encoding: .utf8),
let model = JSONDeserializer<T>.deserializeFrom(json: jsonString) {
observer.onNext(model)
}else {
observer.onError(MoyaError.jsonMapping(element))
}
observer.onCompleted()
return Disposables.create()
}
}
}
}