123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- //
- // SWNetRequest.swift
- // LiteraryHeaven
- //
- // Created by SanW on 2017/8/2.
- // Copyright © 2017年 ONON. All rights reserved.
- //
- import Alamofire
- import UIKit
- // 默认超时时间
- public let bf_timeoutInterval: TimeInterval = 30
- // MARK: - 错误
- /// 错误
- public struct PQError: Error {
- public var msg: String? // 提示信息
- public var code: Int // 错误吗
- public init(msg: String?, code: Int = 0) {
- self.msg = msg
- self.code = code
- }
- public var localizedDescription: String {
- return msg ?? ""
- }
- }
- // MARK: - 网络请求
- /// 网络请求
- public class SWNetRequest: NSObject {
- // static let share = SWNetRequest()
- /// 回调方法
- public typealias completeHander = (_ jsonObject: Any?, _ error: PQError?, _ duration: TimeInterval?) -> Void
- static let sessionManager: Session? = {
- let configuration = URLSessionConfiguration.default
- configuration.timeoutIntervalForRequest = bf_timeoutInterval
- return Session(configuration: configuration, delegate: SessionDelegate(), rootQueue: DispatchQueue(label: "org.alamofire.session.rootQueue"), startRequestsImmediately: true, requestQueue: nil, serializationQueue: nil, interceptor: CMRequestRetrier(), serverTrustManager: nil, redirectHandler: nil, cachedResponseHandler: nil, eventMonitors: [])
- }()
- static let reTrySessionManager: Session? = {
- let configuration = URLSessionConfiguration.default
- configuration.timeoutIntervalForRequest = 5
- return Session(configuration: configuration, delegate: SessionDelegate(), serverTrustManager: nil)
- }()
- /// get请求
- public class func getRequestData(url: String, parames: [String: Any]?, encoding: ParameterEncoding = URLEncoding.default, timeoutInterval: TimeInterval = bf_timeoutInterval, response: @escaping completeHander) {
- requestData(method: .get, encoding: encoding, url: url, parames: parames, timeoutInterval: timeoutInterval) { responseObject, error, timeline in
- response(responseObject, error, timeline)
- }
- }
- /// post请求
- public class func postRequestData(url: String, parames: [String: Any]?, encoding: ParameterEncoding = URLEncoding.default, timeoutInterval: TimeInterval = bf_timeoutInterval, response: @escaping completeHander) {
- requestData(method: .post, encoding: encoding, url: url, parames: parames, timeoutInterval: timeoutInterval) { responseObject, error, timeline in
- response(responseObject, error, timeline)
- }
- }
- // put请求
- public class func putRequestData(url: String, parames: [String: Any]?, encoding: ParameterEncoding = URLEncoding.default, timeoutInterval: TimeInterval = bf_timeoutInterval, response: @escaping completeHander) {
- requestData(method: .put, encoding: encoding, url: url, parames: parames, timeoutInterval: timeoutInterval) { responseObject, error, timeline in
- response(responseObject, error, timeline)
- }
- }
- /// delete请求
- public class func deleteRequestData(url: String, parames: [String: Any]?, encoding: ParameterEncoding = URLEncoding.default, timeoutInterval: TimeInterval = bf_timeoutInterval, response: @escaping completeHander) {
- requestData(method: .delete, encoding: encoding, url: url, parames: parames, timeoutInterval: timeoutInterval) { responseObject, error, timeline in
- response(responseObject, error, timeline)
- }
- }
- /// head请求
- public class func headRequestData(url: String, parames: [String: Any]?, encoding: ParameterEncoding = URLEncoding.default, timeoutInterval: TimeInterval = bf_timeoutInterval, response: @escaping completeHander) {
- requestData(method: .head, encoding: encoding, url: url, parames: parames, timeoutInterval: timeoutInterval) { responseObject, error, timeline in
- response(responseObject, error, timeline)
- }
- }
- /// 网络请求
- fileprivate class func requestData(method: HTTPMethod, encoding: ParameterEncoding, url: String, parames: [String: Any]?, timeoutInterval _: TimeInterval = bf_timeoutInterval, response: @escaping completeHander) {
- if !bf_validURL(url: url) {
- response(nil, PQError(msg: "非法地址", code: 0), nil)
- return
- }
- NTLog(message: "网络请求-发起:url = \(url),parames = \(parames ?? [:])")
- sessionManager?.request(url, method: method, parameters: parames, encoding: encoding, headers: nil, requestModifier: { request in
- request.timeoutInterval = bf_timeoutInterval
- }).responseJSON { jsonResponse in
- switch jsonResponse.result {
- case .success:
- if jsonResponse.data != nil {
- let jsonData: Any = try! JSONSerialization.jsonObject(with: jsonResponse.data!, options: JSONSerialization.ReadingOptions.mutableContainers)
- NTLog(message: "网络请求-成功:url = \(jsonResponse.request?.url?.absoluteString ?? ""),jsonData = \(jsonData)")
- response(jsonData, nil, jsonResponse.metrics?.taskInterval.duration)
- } else {
- response(nil, PQError(msg: "数据为空", code: 1), jsonResponse.metrics?.taskInterval.duration)
- }
- case let .failure(error):
- let errorResult = dealWithError(error: error)
- response(nil, PQError(msg: errorResult.msg, code: errorResult.code), jsonResponse.metrics?.taskInterval.duration)
- NTLog(message: "网络请求-失败:url = \(jsonResponse.request?.url?.absoluteString ?? ""),error = \(String(describing: jsonResponse.error?.localizedDescription))")
- }
- }
- }
- /// 取消网络请求
- /// - Parameter url: 某一个地址,空则取消所有
- /// - Returns: <#description#>
- public class func cancelTask(url: String?) {
- sessionManager?.session.getAllTasks(completionHandler: { tasks in
- tasks.forEach { task in
- if task.currentRequest?.url?.absoluteString == url {
- task.cancel()
- }
- }
- })
- }
- public class func bf_validURL(url: String?) -> Bool {
- if url == nil || (url?.count ?? 0) <= 4 || (!(url?.hasPrefix("http") ?? false) && !(url?.hasPrefix("https") ?? false)) {
- return false
- }
- return true
- }
- /// 获取网络状态
- /// - Returns: <#description#>
- public class func networkStatusDescription() -> String {
- let status = NetworkReachabilityManager(host: "www.baidu.com")?.status
- var statusStr: String!
- switch status {
- case .unknown:
- statusStr = "NETWORK_UNKNOWN"
- case .notReachable:
- statusStr = "NETWORK_NO"
- case .reachable(.cellular):
- statusStr = "4G/5G"
- case .reachable(.ethernetOrWiFi):
- statusStr = "Wi-Fi"
- default:
- statusStr = "NETWORK_UNKNOWN"
- }
- return statusStr
- }
- /// 判断是否有网
- /// - Returns: <#description#>
- public class func isNetReachabled() -> Bool {
- return NetworkReachabilityManager(host: "www.baidu.com")?.status == .reachable(.cellular) || NetworkReachabilityManager(host: "www.baidu.com")?.status == .reachable(.ethernetOrWiFi)
- }
- /// 获取ip地址
- /// - Returns: <#description#>
- public class func ipAddressDescription() -> String {
- var addresses = [String]()
- var ifaddr: UnsafeMutablePointer<ifaddrs>?
- if getifaddrs(&ifaddr) == 0 {
- var ptr = ifaddr
- while ptr != nil {
- let flags = Int32(ptr!.pointee.ifa_flags)
- var addr = ptr!.pointee.ifa_addr.pointee
- if (flags & (IFF_UP | IFF_RUNNING | IFF_LOOPBACK)) == (IFF_UP | IFF_RUNNING) {
- if addr.sa_family == UInt8(AF_INET) || addr.sa_family == UInt8(AF_INET6) {
- var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
- if getnameinfo(&addr, socklen_t(addr.sa_len), &hostname, socklen_t(hostname.count), nil, socklen_t(0), NI_NUMERICHOST) == 0 {
- if let address = String(validatingUTF8: hostname) {
- addresses.append(address)
- }
- }
- }
- }
- ptr = ptr!.pointee.ifa_next
- }
- freeifaddrs(ifaddr)
- }
- return addresses.first ?? "0.0.0.0"
- }
- // 将原始的url编码为合法的url
- public class func bf_urlEncoded(url: String) -> String {
- let encodeUrlString = url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
- return encodeUrlString ?? ""
- }
- // 将编码后的url转换回原始的url
- public class func bf_urlDecoded(url: String) -> String {
- return url.removingPercentEncoding ?? ""
- }
- public class func dealWithError(error: Error?) -> (code: Int, msg: String?) {
- var code: errorCode = .nomal
- var msg: String? = error?.localizedDescription
- if let error = error as? AFError {
- switch error {
- case let .invalidURL(url):
- NTLog(message: "网球请求-处理错误:Invalid URL: \(url) - \(error.localizedDescription)")
- code = .valideUrl
- msg = "请求地址检验失败"
- case let .parameterEncodingFailed(reason):
- NTLog(message: "网球请求-处理错误:parameterEncodingFailed \(error.localizedDescription),Reason: \(reason)")
- case let .multipartEncodingFailed(reason):
- NTLog(message: "网球请求-处理错误:multipartEncodingFailed: \(error.localizedDescription),\(reason)")
- case let .responseValidationFailed(reason):
- NTLog(message: "网球请求-处理错误:responseValidationFailed: \(error.localizedDescription),Reason: \(reason)")
- switch reason {
- case .dataFileNil, .dataFileReadFailed:
- NTLog(message: "网球请求-处理错误:Downloaded file could not be read")
- case let .missingContentType(acceptableContentTypes):
- NTLog(message: "网球请求-处理错误:Content Type Missing: \(acceptableContentTypes)")
- case let .unacceptableContentType(acceptableContentTypes, responseContentType):
- NTLog(message: "网球请求-处理错误:Response content type: \(responseContentType) was unacceptable: \(acceptableContentTypes)")
- case let .unacceptableStatusCode(code):
- NTLog(message: "网球请求-处理错误:Response status code was unacceptable: \(code)")
- case let .customValidationFailed(error: error):
- NTLog(message: "网球请求-处理错误:customValidationFailed: \(error)")
- }
- case let .responseSerializationFailed(reason):
- NTLog(message: "网球请求-处理错误:Response serialization failed: \(error.localizedDescription)")
- NTLog(message: "Failure Reason: \(reason)")
- case let .createUploadableFailed(error: error):
- NTLog(message: "网球请求-处理错误:createUploadableFailed: \(error.localizedDescription)")
- case let .createURLRequestFailed(error: error):
- NTLog(message: "createURLRequestFailed: \(error.localizedDescription)")
- case let .downloadedFileMoveFailed(error: error, source: source, destination: destination):
- NTLog(message: "网球请求-处理错误:downloadedFileMoveFailed: \(error.localizedDescription),\(source),\(destination)")
- case .explicitlyCancelled:
- NTLog(message: "网球请求-处理错误:explicitlyCancelled: \(error.localizedDescription)")
- case let .parameterEncoderFailed(reason: reason):
- NTLog(message: "网球请求-处理错误:parameterEncoderFailed: \(error.localizedDescription),\(reason)")
- case let .requestAdaptationFailed(error: error):
- NTLog(message: "网球请求-处理错误:requestAdaptationFailed: \(error.localizedDescription)")
- case let .requestRetryFailed(retryError: retryError, originalError: originalError):
- NTLog(message: "网球请求-处理错误:requestRetryFailed: retryError = \(retryError),originalError = \(originalError)\(error.localizedDescription)")
- case let .serverTrustEvaluationFailed(reason: reason):
- NTLog(message: "网球请求-处理错误:serverTrustEvaluationFailed: - \(error.localizedDescription),\(reason)")
- case .sessionDeinitialized:
- NTLog(message: "网球请求-处理错误:sessionDeinitialized: \(error.localizedDescription)")
- case let .sessionInvalidated(error: error):
- NTLog(message: "网球请求-处理错误:sessionInvalidated: \(String(describing: error?.localizedDescription))")
- case let .sessionTaskFailed(error: failError):
- NTLog(message: "网球请求-处理错误:sessionTaskFailed:error = \(error) \(error.localizedDescription)")
- code = errorCode.init(rawValue: (failError as? NSError)?.code ?? 1) ?? .nomal
- if code == .netLost || code == .tomeOut {
- msg = "网络不给力"
- }
- case let .urlRequestValidationFailed(reason: reason):
- NTLog(message: "网球请求-处理错误:urlRequestValidationFailed: \(error.localizedDescription),\(reason)")
- }
- NTLog(message: "网球请求-处理错误:Underlying error: \(String(describing: error.underlyingError))")
- } else {
- NTLog(message: "网球请求-处理错误:Unknown error: \(String(describing: error))")
- }
- return (code.rawValue, msg)
- }
- }
- /** 打印 */
- func NTLog<T>(message: T, fileName: String = #file, methodName: String = #function, lineNumber: Int = #line) {
- #if DEBUG
- print("👉func: \((fileName.components(separatedBy: "/").last)!).\(methodName)\n time: \(Int64(CFAbsoluteTimeGetCurrent() * 1000))\n line: \(lineNumber)\n message: \(message)👈")
- #else
- #endif
- }
- class CMRequestRetrier: RequestInterceptor {
- func retry(_: Request, for _: Session, dueTo _: Error, completion: @escaping (RetryResult) -> Void) {
- completion(.doNotRetry)
- }
- }
- enum errorCode: Int {
- case nomal = 1
- case valideUrl = 2
- case tomeOut = -1001
- case netLost = -1009
- }
|