單個請求可使用 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
}