moya(二)

單個請求可使用 moya(一)描述

當多個請求的時候,可以封裝一個manager

let HOSTURL = "https://api.mamahao.com"
let HOSTWEBURL = "http://221.7.181.199:19301"


enum  APIManager {
    case getRequest(APIName: String ,isTouch: Bool, body: Dictionary<String, Any>? ,isShow: Bool,title: String?)
    case postRequest(APIName: String ,isTouch: Bool, body: Dictionary<String, Any>? ,isShow: Bool,title: String?)
}

extension APIManager:TargetType {
    
    var path: String {
        return ""
    }
    
    var method: Moya.Method {
        switch self {
        case .getRequest(_, _, _, _, _):
            return .get
        case .postRequest(_, _, _, _, _):
            return .post
        }
    }
    
    var sampleData: Data {
        return "{}".data(using: String.Encoding.utf8)!
    }

    var task: Task {
        switch self {
        case .getRequest(_, _,let postDict, _, _):
            return .requestParameters(parameters: postDict!, encoding: URLEncoding.default)
        case .postRequest(_, _, let postDict, _, _):
            return .requestParameters(parameters: postDict!, encoding: URLEncoding.default)
        }
    }
    
    //設置header
    var headers: [String : String]? {
        let sessionId =  ""
        return [
            "Content-Type" : "application/x-www-form-urlencoded;charset=UTF-8",
            "COOKIE" :  "JSESSIONID=\(sessionId)",
            "Accept": "application/json;application/octet-stream;text/html,text/json;text/plain;text/javascript;text/xml;application/x-www-form-urlencoded;image/png;image/jpeg;image/jpg;image/gif;image/bmp;image/*"
        ]
    }
    
    /// The target's base `URL`.
    var baseURL: URL {
        switch self {
        case .postRequest(_, _, _, _, _):
            #if DEBUG
            return URL(string: HOSTURL)!
            #else
            return URL(string: HOSTURL)!
            #endif
        case .getRequest(_, _, _, _, _):
            #if DEBUG
            return URL(string: "http://ws.gx10010.com/mobileservice")!
            #else
            return URL(string: "http://ws.gx10010.com/mobileservice")!
            #endif
        }
    }
}

封裝一個請求manager

//
//  HTNetWorking.swift
//  love100
//
//  Created by fishycx on 2019/8/2.
//  Copyright © 2019 fishycx. All rights reserved.
//

import Foundation
import Moya
import Alamofire

// MARK: - Provider setup系統方法轉換json數據

private func JSONResponseDataFormatter(_ data: Data) -> Data {
    do {
        let dataAsJSON = try JSONSerialization.jsonObject(with: data)
        let prettyData =  try JSONSerialization.data(withJSONObject: dataAsJSON, options: .prettyPrinted)
        return prettyData
    } catch {
        return data // fallback to original data if it can't be serialized.
    }
}

private func JSONResponseFormatter(_ data: Data) -> Dictionary<String, Any>? {
    do {
        let dataAsJSON = try JSONSerialization.jsonObject(with: data)
        return dataAsJSON as? Dictionary<String, Any>
    } catch {
        return nil // fallback to original data if it can't be serialized.
    }
}

// MARK: - 默認的網絡提示請求插件
let spinerPlugin = NetworkActivityPlugin { (state,target) in
    if state == .began {
        print("我開始請求")
        UIApplication.shared.isNetworkActivityIndicatorVisible = true
    } else {
        print("我結束請求")
        UIApplication.shared.isNetworkActivityIndicatorVisible = false
    }
}

 //MARK: - 自定義的網絡提示請求插件
let myNetworkPlugin = TNetworkActivityPlugin { (state,target) in

    let api = target as! APIManager

    if state == .began {
        //        SwiftSpinner.show("Connecting...")

//        if api.show {
//            print("我可以在這裏寫加載提示")
//            if !api.touch {
//                print("我可以在這裏寫禁止用戶操作,等待請求結束")
//            }
//            //            SVPHUDTool.showHUD(api.touch,api.title)
//        }

        UIApplication.shared.isNetworkActivityIndicatorVisible = true
    } else {
//        //        SwiftSpinner.show("request finish...")
//        //        SwiftSpinner.hide()
//
//        if api.show {
//            //           SVPHUDTool.dismiss()
//        }

        print("我結束請求")
        UIApplication.shared.isNetworkActivityIndicatorVisible = false

    }
}

// MARK: - 設置請求頭部信息
let myEndpointClosure = { (target: APIManager) -> Endpoint in
    let sessionId =  ""
    let url = target.baseURL.appendingPathComponent(target.path).absoluteString
    let endpoint = Endpoint.init(url: url, sampleResponseClosure:  { .networkResponse(200, target.sampleData) }, method: target.method, task: target.task, httpHeaderFields: target.headers)
    return endpoint.adding(newHTTPHeaderFields: [
        "Content-Type" : "application/x-www-form-urlencoded",
        "COOKIE" : "JSESSIONID=\(sessionId)",
        "Accept": "application/json;application/octet-stream;text/html,text/json;text/plain;text/javascript;text/xml;application/x-www-form-urlencoded;image/png;image/jpeg;image/jpg;image/gif;image/bmp;image/*"
        ])
}

// MARK: - 設置請求頭部信息
var endpointClosure = { (target: APIManager) -> Endpoint in
    let sessionId =  ""
    let url = target.baseURL.appendingPathComponent(target.path).absoluteString
    var endpoint: Endpoint = Endpoint(
        url: url,
        sampleResponseClosure: {.networkResponse(200, target.sampleData)},
        method: target.method,
        task: target.task,
        httpHeaderFields: target.headers
    )
    return endpoint.adding(newHTTPHeaderFields: [
        "Content-Type" : "application/x-www-form-urlencoded",
        "COOKIE" : "JSESSIONID=\(sessionId)",
        "Accept": "application/json;application/octet-stream;text/html,text/json;text/plain;text/javascript;text/xml;application/x-www-form-urlencoded;image/png;image/jpeg;image/jpg;image/gif;image/bmp;image/*"
        ])
}

// MARK: - 設置請求超時時間
let requestClosure = { (endpoint: Endpoint, done: @escaping MoyaProvider<APIManager>.RequestResultClosure) in
    //    guard var request = endpoint.urlRequest else { return }
    //    request.timeoutInterval = 30    //設置請求超時時間
    //    done(.success(request))
    do {
        var request: URLRequest = try endpoint.urlRequest()
        request.timeoutInterval = 30    //設置請求超時時間
        done(.success(request))
    } catch  {
        print("錯誤了 \(error)")
    }
}

// MARK: - 設置請求超時時間
//let RxRequestClosure = { (endpoint: Endpoint<NetAPIManager>, done: @escaping ReactiveSwiftMoyaProvider<NetAPIManager>.RequestResultClosure) in
//
//    guard var request = endpoint.urlRequest else { return }
//
//    request.timeoutInterval = 40    //設置請求超時時間
//    done(.success(request))
//}

/// 關閉https認證

let serverTrustPolicies: [String: ServerTrustPolicy] = [
    
    "172.16.88.106": .pinCertificates(certificates: ServerTrustPolicy.certificates(), validateCertificateChain: true, validateHost: true),
    "insecure.expired-apis.com": .disableEvaluation
    
]

//performDefaultEvaluation:使用默認的server trust評估,允許我們控制是否驗證challenge提供的host。
//pinCertificates:使用pinned certificates來驗證server trust。如果pinned certificates匹配其中一個服務器證書,那麼認爲server trust是有效的。
//pinPublicKeys:使用pinned public keys來驗證server trust。如果pinned public keys匹配其中一個服務器證書公鑰,那麼認爲server trust是有效的。
//disableEvaluation:禁用所有評估,總是認爲server trust是有效的。
//customEvaluation:使用相關的閉包來評估server trust的有效性,我們可以完全控制整個驗證過程。但是要謹慎使用。

let configuration: URLSessionConfiguration = {
    let configuration = URLSessionConfiguration.default
    configuration.httpAdditionalHeaders = Manager.defaultHTTPHeaders
    return configuration
    
}()

let delegate: SessionDelegate = {
    let delegate = SessionDelegate()
    delegate.sessionDidReceiveChallenge = { session, challenge in
        //認證服務器證書
        if challenge.protectionSpace.authenticationMethod
            == NSURLAuthenticationMethodServerTrust {
            print("服務端證書認證!")
            let serverTrust:SecTrust = challenge.protectionSpace.serverTrust!
            let certificate = SecTrustGetCertificateAtIndex(serverTrust, 0)!
            let remoteCertificateData
                = CFBridgingRetain(SecCertificateCopyData(certificate))!
            let cerPath = Bundle.main.path(forResource: "tomcat", ofType: "cer")!
            let cerUrl = URL(fileURLWithPath:cerPath)
            let localCertificateData = try! Data(contentsOf: cerUrl)
            
            if (remoteCertificateData.isEqual(localCertificateData) == true) {
                
                let credential = URLCredential(trust: serverTrust)
                challenge.sender?.use(credential, for: challenge)
                return (URLSession.AuthChallengeDisposition.useCredential,
                        URLCredential(trust: challenge.protectionSpace.serverTrust!))
                
            } else {
                return (.cancelAuthenticationChallenge, nil)
            }
        }
            //認證客戶端證書
        else if challenge.protectionSpace.authenticationMethod
            == NSURLAuthenticationMethodClientCertificate {
            print("客戶端證書認證!")
            //獲取客戶端證書相關信息
            let identityAndTrust:IdentityAndTrust = extractIdentity();
            
            let urlCredential:URLCredential = URLCredential(
                identity: identityAndTrust.identityRef,
                certificates: identityAndTrust.certArray as? [AnyObject],
                persistence: URLCredential.Persistence.forSession);
            
            return (.useCredential, urlCredential);
        }
            // 其它情況(不接受認證)
        else {
            print("其它情況(不接受認證)")
            return (.cancelAuthenticationChallenge, nil)
        }
    }
    return delegate
}()

let myManager = Manager (
    configuration: configuration,
    delegate:delegate,
    serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
//        let configuration = URLSessionConfiguration.default
//        configuration.httpAdditionalHeaders = Manager.defaultHTTPHeaders
//
//        let manager = Manager(configuration: configuration)
//        manager.startRequestsImmediately = false
//        return manager
//
)



let provider = MoyaProvider<APIManager>(requestClosure: requestClosure,                manager:myManager)

let MyAPIProvider = MoyaProvider<APIManager>(endpointClosure: myEndpointClosure,requestClosure: requestClosure, plugins: [NetworkLoggerPlugin(verbose: true, responseDataFormatter: JSONResponseDataFormatter), myNetworkPlugin])

//let RxAPIProvider = RsAPIProvider<NetAPIManager>(endpointClosure: endpointClosure,requestClosure: requestClosure, plugins: [NetworkLoggerPlugin(verbose: true, responseDataFormatter: JSONResponseDataFormatter),myNetworkPlugin])

//let RsAPIProvider = ReactiveSwiftMoyaProvider<NetAPIManager>(endpointClosure: myEndpointClosure,requestClosure: requestClosure,stubClosure: MoyaProvider.immediatelyStub, plugins: [NetworkLoggerPlugin(verbose: true, responseDataFormatter: JSONResponseDataFormatter),myNetworkPlugin])


// MARK: -取消所有請求
func cancelAllRequest() {
    //    MyAPIProvider.manager.session.invalidateAndCancel()  //取消所有請求
    MyAPIProvider.manager.session.getTasksWithCompletionHandler { dataTasks, uploadTasks, downloadTasks in
        dataTasks.forEach { $0.cancel() }
        uploadTasks.forEach { $0.cancel() }
        downloadTasks.forEach { $0.cancel() }
    }
    
    //let sessionManager = Alamofire.SessionManager.default
    //sessionManager.session.getTasksWithCompletionHandler { dataTasks, uploadTasks, downloadTasks in
    //    dataTasks.forEach { $0.cancel() }
    //    uploadTasks.forEach { $0.cancel() }
    //    downloadTasks.forEach { $0.cancel() }
    //}
    
    
    
}



func blockHander(theBlock:@escaping (String)->()) {
    theBlock("myBlock")
}

// MARK: -創建一個Moya請求
public func sendMyRequest(_ name: String, touch:Bool? = true, show: Bool? = true, titleString: String? = nil, postDict: Dictionary<String, Any>? = nil,
                          success:@escaping (Dictionary<String, Any>?)->(),
                          failure:@escaping (MoyaError)->()) -> Cancellable? {
    
    let request = MyAPIProvider.request(.getRequest(APIName:name,isTouch: touch!, body:postDict ,isShow: show!, title: titleString)) { result in
        
        //        do {
        //            let response = try result.dematerialize()
        ////            let value = try response.mapNSArray()
        ////            print("maya 原生 \(value)")
        //
        //
        //
        //        } catch {
        //
        //
        //        }
        
        
        switch result {
        case let .success(moyaResponse):
            let data =  moyaResponse.data
            let statusCode =  moyaResponse.statusCode
            print("MyAPIProvider : \(data) ---  ----- \(statusCode)")
            
            guard !data.isEmpty else{
                success(nil)
                return
            }
            
            let dict = JSONResponseFormatter(data)
            print("解密後的數據 :\(dict ?? [:]) ")
            success((dict))
            
        case let .failure(error):
            
            print(error)
            failure(error)
        }
    }
    
    return request
}

// MARK: -創建一個Moya請求
public func sendPostMyRequest(_ name: String, touch:Bool? = true, show: Bool? = true, titleString: String? = nil, postDict: Dictionary<String, Any>? = nil,
                              success:@escaping (Dictionary<String, Any>?)->(),
                              failure:@escaping (MoyaError)->()) -> Cancellable? {
    
    let request = MyAPIProvider.request(.postRequest(APIName:name,isTouch: touch!, body:postDict ,isShow: show!, title: titleString)) { result in
        
        //        do {
        //            let response = try result.dematerialize()
        ////            let value = try response.mapNSArray()
        ////            print("maya 原生 \(value)")
        //
        //
        //
        //        } catch {
        //
        //
        //        }
        
        
        
        switch result {
        case let .success(moyaResponse):
            
            let data =  moyaResponse.data
            let statusCode =  moyaResponse.statusCode
            //            MyDDLog("MyAPIProvider : \(data) ---  ----- \(statusCode)")
            
            let response  = moyaResponse.response
            let cookies = HTTPCookie.cookies(withResponseHeaderFields: response?.allHeaderFields as! [String : String], for: (response?.url)!)
            print("response cookies: \(cookies) ")
            
            guard !data.isEmpty else{
                //                MyDDLog("data數據爲空 ")
                success(nil)
                return
            }
            
            guard statusCode == 200 else{
                //                MyDDLog("非200 錯誤返回來 ")
                success(nil)
                return
            }
            
            let dict =  JSONResponseFormatter(data)
            print("解密後的數據 :\(dict ?? [:]) ")
            success(dict)
            
        case let .failure(error):
            
            print(error)
            failure(error)
        }
    }
    
    return request
}

//// MARK: -創建一個ReactiveSwiftMoyaProvider請求
//func sendReactiveSwiftRequest(_ name: String, touch:Bool? = true, show: Bool? = true, titleString: String? = nil, postDict: Dictionary<String, Any>? = nil,
//                              success:@escaping (Dictionary<String, Any>)->(),
//                              failure:@escaping (MoyaError)->()) -> Disposable? {
//
//    let request = MyAPIProvider.reactive.request(.postRequest(APIName:name,isTouch: touch!, body:postDict ,isShow: show!, title: titleString)).start { event in
//        switch event {
//        case let .value(response):
//            do {
//                let any = try response.mapJSON()
//                let string = try response.mapString()
//
//                print("ReactiveSwift  : \(any) --- \(string)")
//
//                success(any as! Dictionary<String, Any>)
//            }
//            catch {
//
//            }
//
//        case let .failed(error):
//            print(error)
//            failure(error)
//        default:
//            break
//        }
//    }
//
//    //    request.dispose()   釋放信號
//
//    return request
//}


//// MARK: -創建一個RxSwiftMoyaProvider請求
//func sendRxSwiftRequest(_ name: String, touch:Bool? = true, show: Bool? = true, titleString: String? = nil, postDict: Dictionary<String, Any>? = nil,
//                        success:@escaping (Dictionary<String, Any>)->(),
//                        failure:@escaping (MoyaError)->()) -> Disposable? {
//
//
//    let request = MyAPIProvider.rx.request(.postRequest(APIName:name,isTouch: touch!, body:postDict ,isShow: show!, title: titleString)).subscribe { event in
//        switch event {
//        case let .success(response):
//
//            do {
//                let any = try response.mapJSON()
//                let string = try response.mapString()
//
//                print("RxSwift  : \(any) --- \(string)")
//
//                success(any as! Dictionary<String, Any> )
//            }
//            catch {
//                print("錯誤了")
//            }
//
//        case let .error(error):
//            print(error)
//
//            failure(error as! MoyaError)
//
//        }
//    }
//
//
//    return request as? Disposable
//}

// MARK: -Alamofire原生用法
func sendAlamofireRequest(){
    //POST request
    let postsEndpoint: String = "http://ny.gx10010.com/mobile-service/mapp/json_in_plain.do"
    let jsonDic = ["msg":"{\"@class\":\"com.ailk.gx.mapp.model.GXCDatapackage\",\"header\":{\"@class\":\"com.ailk.gx.mapp.model.GXCHeader\",\"bizCode\":\"cg0004\",\"identityId\":null,\"respCode\":null,\"respMsg\":null,\"mode\":\"1\",\"sign\":null},\"body\":{\n  \"expand\" : null,\n  \"@class\" : \"com.ailk.gx.mapp.model.req.CG0004Request\",\n  \"phoneNo\" : \"13213451345\"\n}}"]
    Alamofire.request(postsEndpoint, method: .post, parameters: jsonDic, encoding: URLEncoding.default,headers:[
        "Content-Type" : "application/x-www-form-urlencoded",
        "COOKIE" : "",
        "Accept": "application/json;application/octet-stream;text/html,text/json;text/plain;text/javascript;text/xml;application/x-www-form-urlencoded;image/png;image/jpeg;image/jpg;image/gif;image/bmp;image/*"
        ]).responseJSON { response in
            //do something with response
            
            print("Alamofire 原生 \(response)")
        }.responseString { (responseString) in
            print("Alamofire 原生 \(responseString)")
    }
}


func configureAlamofireManager() {
    let manager = Manager.default
    manager.delegate.sessionDidReceiveChallenge = { session, challenge in
        var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling
        var credential: URLCredential?
        
        if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
            disposition = URLSession.AuthChallengeDisposition.useCredential
            credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
        } else {
            if challenge.previousFailureCount > 0 {
                disposition = .cancelAuthenticationChallenge
            } else {
                credential = manager.session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace)
                
                if credential != nil {
                    disposition = .useCredential
                }
            }
        }
        return (disposition, credential)
    }
}

//客戶端,服務端證書雙向認證
func twoAlamofireManager() {
    //認證相關設置
    let manager = SessionManager.default
    manager.delegate.sessionDidReceiveChallenge = { session, challenge in
        //認證服務器證書
        if challenge.protectionSpace.authenticationMethod
            == NSURLAuthenticationMethodServerTrust {
            print("服務端證書認證!")
            let serverTrust:SecTrust = challenge.protectionSpace.serverTrust!
            let certificate = SecTrustGetCertificateAtIndex(serverTrust, 0)!
            let remoteCertificateData
                = CFBridgingRetain(SecCertificateCopyData(certificate))!
            let cerPath = Bundle.main.path(forResource: "tomcat", ofType: "cer")!
            let cerUrl = URL(fileURLWithPath:cerPath)
            let localCertificateData = try! Data(contentsOf: cerUrl)
            
            if (remoteCertificateData.isEqual(localCertificateData) == true) {
                
                let credential = URLCredential(trust: serverTrust)
                challenge.sender?.use(credential, for: challenge)
                return (URLSession.AuthChallengeDisposition.useCredential,
                        URLCredential(trust: challenge.protectionSpace.serverTrust!))
                
            } else {
                return (.cancelAuthenticationChallenge, nil)
            }
        }
            //認證客戶端證書
        else if challenge.protectionSpace.authenticationMethod
            == NSURLAuthenticationMethodClientCertificate {
            print("客戶端證書認證!")
            //獲取客戶端證書相關信息
            let identityAndTrust:IdentityAndTrust = extractIdentity();
            
            let urlCredential:URLCredential = URLCredential(
                identity: identityAndTrust.identityRef,
                certificates: identityAndTrust.certArray as? [AnyObject],
                persistence: URLCredential.Persistence.forSession);
            
            return (.useCredential, urlCredential);
        }
            // 其它情況(不接受認證)
        else {
            print("其它情況(不接受認證)")
            return (.cancelAuthenticationChallenge, nil)
        }
    }
    
    
}

//客戶端證書單向認證
func alamofireManager() {
    //自簽名網站地址
    let selfSignedHosts = ["192.168.1.112", "www.hangge.com"]
    //認證相關設置
    let manager = SessionManager.default
    manager.delegate.sessionDidReceiveChallenge = { session, challenge in
        //認證服務器(這裏不使用服務器證書認證,只需地址是我們定義的幾個地址即可信任)
        if challenge.protectionSpace.authenticationMethod
            == NSURLAuthenticationMethodServerTrust
            && selfSignedHosts.contains(challenge.protectionSpace.host) {
            print("服務器認證!")
            let credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
            return (.useCredential, credential)
        }
            //認證客戶端證書
        else if challenge.protectionSpace.authenticationMethod
            == NSURLAuthenticationMethodClientCertificate {
            print("客戶端證書認證!")
            //獲取客戶端證書相關信息
            let identityAndTrust:IdentityAndTrust = extractIdentity();
            
            let urlCredential:URLCredential = URLCredential(
                identity: identityAndTrust.identityRef,
                certificates: identityAndTrust.certArray as? [AnyObject],
                persistence: URLCredential.Persistence.forSession);
            
            return (.useCredential, urlCredential);
        }
            // 其它情況(不接受認證)
        else {
            print("其它情況(不接受認證)")
            return (.cancelAuthenticationChallenge, nil)
        }
    }
    
    
}

//獲取客戶端證書相關信息
func extractIdentity() -> IdentityAndTrust {
    var identityAndTrust:IdentityAndTrust!
    var securityError:OSStatus = errSecSuccess
    
    let path: String = Bundle.main.path(forResource: "mykey", ofType: "p12")!
    let PKCS12Data = NSData(contentsOfFile:path)!
    let key : NSString = kSecImportExportPassphrase as NSString
    let options : NSDictionary = [key : "123456"] //客戶端證書密碼
    //create variable for holding security information
    //var privateKeyRef: SecKeyRef? = nil
    
    var items : CFArray?
    
    securityError = SecPKCS12Import(PKCS12Data, options, &items)
    
    if securityError == errSecSuccess {
        let certItems:CFArray = (items as CFArray?)!;
        let certItemsArray:Array = certItems as Array
        let dict:AnyObject? = certItemsArray.first;
        if let certEntry:Dictionary = dict as? Dictionary<String, AnyObject> {
            // grab the identity
            let identityPointer:AnyObject? = certEntry["identity"];
            let secIdentityRef:SecIdentity = (identityPointer as! SecIdentity?)!
            print("\(String(describing: identityPointer))  :::: \(secIdentityRef)")
            // grab the trust
            let trustPointer:AnyObject? = certEntry["trust"]
            let trustRef:SecTrust = trustPointer as! SecTrust
            print("\(String(describing: trustPointer))  :::: \(trustRef)")
            // grab the cert
            let chainPointer:AnyObject? = certEntry["chain"]
            identityAndTrust = IdentityAndTrust(identityRef: secIdentityRef,
                                                trust: trustRef, certArray:  chainPointer!)
        }
    }
    return identityAndTrust;
}

//定義一個結構體,存儲認證相關信息
struct IdentityAndTrust {
    var identityRef:SecIdentity
    var trust:SecTrust
    var certArray:AnyObject
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章