AutoNet-Ios(網絡架構, 加入了攔截器概念)
AutoNet封裝了URLSession并使用HandyJSON處理了Json資料。 提供了友好簡易且強大的回調及API去處理繁瑣的網絡請求代碼,加入了攔截器概念可更加友善使用者使用及監控網絡請求, 使用者直接拿到實體類, 是Ios開發網絡應用更加簡單, 隻需關注業務即可。
Git位址
1. Ios版本:
ios版AutoNet
2. Android版本:
Android版AutoNet
AutoNet 技術交流群:
QQ: 141027175
特色
- 使用簡單、調用友善
- 加入攔截器概念, 使用者可以更加友善的制定和監控自己的請求
- 可動态添加和修改頭部
- 可對請求參數資料進行加密
- 可自主處理傳回的頭部資料
- 可自主處理傳回的body資料
- 可自定義傳回資料的類型
- 可定義固定、靈活及臨時的域名、頭部資訊(優先級: 臨時>靈活>固定。 有效性: 固定 >= 靈活 > 臨時)
- 支援網絡政策(網絡、本地、先本地後網絡、先網絡後本地)
- 支援上傳檔案和下載下傳檔案
- 可直接獲得上遊的發射器, 使用者自己進行操作結果。(eg: 使用zip去合并多個請求等)
Pod依賴
pod 'AutoNet', '~> 1.0.3'
簡易使用demo
攔截器介紹
1. 攔截器協定
/**
* 攔截器協定
**/
public protocol Interceptor {
/**
* 攔截器
* chain: 資料載體及回饋
* responseBack: 用于上層向下層回報資料
**/
func intercept(chain: Chain, responseBack: @escaping AutoNetClosure.responseBack) ->Void
}
2. 事例:
1. AutoNet内部自帶的一個預設日志攔截器
/**
* 預設日志實作(使用者可根據自己的需求自定義攔截器去制定)
**/
class DefaultLogInterceptor: Interceptor{
func intercept(chain: Chain, responseBack: @escaping AutoNetClosure.responseBack) {
let request = chain.request()
let url = request.getUrl()
let method = request.getMethod()
let params = request.getParam()?.getParams()
let headers = request.getHeader()?.getHeaders()
print("-------------------------------------------------------")
print("---------------------網絡請求日志------------------------")
print("-\t請求位址: \(url)")
print("-\t請求方式: \(method)")
print("-\t請求頭部參數:")
if(headers == nil || headers!.count <= 0){
print("\t\t\t無")
}else{
for key in headers!.keys{
print("\t\t\t\(key): \(headers![key] ?? "")")
}
}
print("-\t請求參數:")
if(params == nil || params!.count <= 0){
print("\t\t\t無")
}else{
for key in params!.keys{
print("\t\t\t\(key): \(String(describing: params![key]))")
}
}
let bgnTime = Date().timeIntervalSince1970
chain.proceed(request: request) { (response) in
print("-\t資料傳回:")
print("\t\t\t\(response ?? "空")")
let endTime = Date().timeIntervalSince1970
print("-------------耗時:\(endTime - bgnTime)ms----------------")
print("-------------------------------------------------------")
responseBack(response)
}
}
}
2. 自定義參數攔截器
final class ParamsInterceptor: Interceptor{
func intercept(chain: Chain, responseBack: @escaping AutoNetClosure.responseBack) {
var request = chain.request()
let header = request.getHeader()
// 構造新的頭部資料
let newHeader = header?.newBuilder(isFollow: true)
.addHeader(key: "token", value: "a")
.addHeader(key: "userId", value: "0")
.build()
let param = request.getParam()
// 構造新的參數資料
let newParam = param?.newBuilder(isFollow: true)
.addParam(key: "params1", value: "value1")
.addParam(key: "params2", value: "value2")
.build()
request = request.newBuilder()
.setHeaders(header: newHeader)
.setParam(param: newParam).build()
chain.proceed(request: request) { (response) in
responseBack(response)
}
}
}
AutoNet提供出的Error
/**
* AutoNet 錯誤分類
**/
public enum AutoNetError : Error{
/**
* 空資料錯誤(使用者在攔截處理空時,可使用該錯誤)
*/
case EmptyError
/**
* 網絡錯誤(當網絡錯誤,AutoNet會自動抛出該錯誤)
*/
case NetError
/**
* 自定義錯誤(自定義錯誤, code及message可自定義。 其中json轉換錯誤時AutoNet就會以該形式抛出)
*/
case CustomError(code: Int, message: String?)
}
使用
1. 初始化
1.1 AutoNetConfig(配置AutoNet的基本配置) 注意: 該配置基本是固定的, eg: 域名, 頭部資料等
- 設定是否開啟預設的網絡日志功能
- 設定預設域名(key: default)
- 設定多個域名
- 設定頭部參數
- 設定攔截器
1.2 AutoNet的初始化操作
AutoNet.getInstance().initAutoNet(config: config)
.setEncryptionCallback(encryptionCallback: { (flag, encryptionContent) -> String in
// 可通過key去加密參數
return encryptionContent ?? ""
})
.setHeadsCallback { (flag, headers) in
// 請求傳回頭部資料回調
}.setBodyCallback { (flag, response, emmit) -> Bool in
// 自己處理需要傳回true
return false
}
可以全局修改域名和頭部資料等, eg:
AutoNet.updateOrInsertDomainNames(key: "T##String", value: "T##String")
AutoNet.updateOrInsertHead(key: "T##String", value: "T##Any")
2 常用的閉包介紹
在請求時需要需要關注那些操作就實作那些協定即可, AutoNet會自動判斷及給你想要滴
2.1 資料相關的閉包
/**
* 資料相關回調
**/
public final class AutoNetDataClosure<T> {
/**
* 成功回調
* t: 要傳回的實體類對象
**/
public typealias onSuccess = (_ t: T) ->Void
/**
* 失敗回調
* err: 錯誤
**/
public typealias onError = (_ err: Error) ->Void
/**
* 資料空回調
**/
public typealias onEmpty = () -> Void
/**
* 本地處理回調
* params: 請求參數
* emitter: 資料上遊發射器
* @return true: 攔截AutoNet處理, false: 結果交給AutoNet繼續處理(這裡需要注意: 如果本地處理, 需要傳回true, 在本地操作中隻要傳回false, AutoNet分分鐘鐘給你一個AutoNetError.Empty, 因為AutoNet真的不知道如何處理呢)
**/
public typealias optLocalData = (_ params: Dictionary<String, Any>?, _ emitter: RxSwift.AnyObserver<T>) -> Bool
}
2.2 資料轉換相關閉包
/**
* 資料轉換相關回調
**/
public final class AutoNetConvertClosure<T, Z>{
/**
* 資料提前處理轉換
* t: 需要轉換的前提類對象
* emitter: RxSwitf 上遊發射器
* @return true: 攔截AutoNet處理, false: 結果交給AutoNet繼續處理
**/
public typealias handlerBefore = (_ t: T, _ emitter: RxSwift.AnyObserver<Z>) -> Bool
}
2.3 全局資料回調相關閉包
/**
* 網絡資料body回調(全局)
* flag: 請求辨別, 可追蹤指定請求
* body: 請求傳回body内容
* emitter: 上遊發射器(可自定義傳回或者個性化處理)
* @return: true=> 攔截AutoNet處理, 交給自己處理, false=> 交于AutoNet自行處理
**/
public typealias body = (_ flag: Any?, _ body: String, _ emitter: AutoNetSimpleAnyObserver) -> Bool
/**
* 網絡頭部資料的傳回回調(全局)
* flag: 請求辨別, 可追蹤指定請求
* headers: 請求傳回的頭部資料
**/
public typealias head = (_ flag: Any?, _ headers: Headers) -> Void
/**
* 參數解密回調
* key: 加密辨別, 可根據不同的辨別進行多個加密方式
* encryptionContent: 需要加密的資料
* @return: 加密後的資料
**/
public typealias encryption = (_ key: Int, _ encryptionContent: String?) -> String
2.3
/**
* 檔案相關的閉包
**/
final class AutoNetFileClosure{
/**
* 檔案進度回調
* progress: 進度(0~100)
**/
public typealias onPregress = (_ progress: Float) -> Void
/**
* 檔案完後回調
* path: 檔案路徑
**/
public typealias onComplete = (_ path: String) -> Void
}
3 網絡調用
// AutoNet請求執行個體1: 預設傳回類型為AutoNet定義好的AutoNetDefaultResponse(其中傳回的資料存在對象内部response裡)
1. AutoNet.getInstance().createNet()
// AutoNet請求執行個體2: 不需要二次轉換,AutoNet會自動把請求資料進行轉換
2. AutoNet.getInstance().createNet(HandyJSON)
// AutoNet請求執行個體3: 需要二次轉換自己關心的資料, 需要複寫handlerBefore方法
3. AutoNet.getInstance().createNet(HandyJSON, ExpectResponse)
// 設定請求位址(去除域名)
.setSuffixUrl(suffixUrl: "T##String")
// 設定追蹤标志
.setFlag(flag: "T##Any")
// 設定請求參數
.setParam(key: "T##String", value: "T##Any")
.setParams(params: Dictionary<String, Any>())
// 發起post請求
.doPost()
// 發起get請求
.doGet()
// 發起put請求
.doPut()
// 發起delete請求
.doDelete()
// 設定使用的域名的key(預設default)
.setDomainNameKey(domainNameKey: "T##String")
// 設定請求方式
.setNetPattern(netPattern: AutoNetPattern.get)
// 設定請求政策
.setNetStrategy(netStrategy: AutoNetStrategy.NET)
// 設定請求類型(JSON/FORM/STREAM/OTHER)
.setReqType(reqType: AutoNetType.JSON)
// 設定傳回類型(JSON/FORM/STREAM/OTHER)
.setResType(resType: AutoNetType.JSON)
// 設定額外參數(主要解決動态的拼在URL中的參數。eg: www.xxx.com/news/1, 最後的那個動态的參數1)
.setExtraDynamicParam(extraDynamicParam: "T##String")
// 設定連接配接逾時時間
.setConnectOutTime(outTime: 5000)
// 設定讀取逾時時間
.setReadOutTime(readOutTime: 5000)
// 設定寫入逾時時間
.setWriteOutTime(writeOutTime: 5000)
// 設定解密的key
.setEncryptionKey(encryptionKey: 0)
// 是否開啟加密功能
.isEncryption(isEncryption: true)
// 設定MediaType
.setMediaType(mediaType: "T##String")
// 下載下傳檔案
.setPullFileParams(filePath: "T##String", fileName: "T##String")
// 上傳檔案
.setPushFileParams(pushFileKey: "T##String", filePath: "T##String")
// 設定頭部資料(臨時有效)
.setHeads(heads: Dictionary<String, Any>())
// 擷取上遊發射者
(1).getObservable()
// 開始請求
(2).start(...)
4 擷取上遊并處理(已zip合并為例, 這裡隻是用了兩個, 其實RxSwift提供了好多, 當然還有其他用法,詳情可以看RxSwift的用法)
// json 資料
let first: Observable = AutoNet.getInstance().createNet(BaseResponse<String>())
.doGet()
.setDomainNameKey(domainNameKey: "test")
.setFlag(flag: "xiaoxige")
.setSuffixUrl(suffixUrl: "/user/test")
.getObservable()
// 百度資料
let second:Observable = AutoNet.getInstance().createNet()
.doGet()
.setFlag(flag: "zhuxiaoan")
.getObservable()
Observable<ContainEntity>.zip(first, second) { (firstEntity, secondEntity) -> ContainEntity in
// 合并
let containEntity: ContainEntity = ContainEntity()
containEntity.setFirst(first: firstEntity.getMessage())
containEntity.setSecond(second: secondEntity.getResponse())
return containEntity
}.subscribe(onNext: { (entity) in
print("entity.first = \(entity.getFirst()), entity.second = \(entity.getSecond())")
}, onError: { (erro) in
print("出錯了 error = \(erro)")
}, onCompleted: {
}) {
}
簡單的例子
初始化
let config = AutoNetConfig.Builder()
.setIsOpenDefaultLog(isOpen: true)
.setDefaultDomainName(value: "http://xxx.xxx.com")
.build()
AutoNet.getInstance().initAutoNet(config: config)
.setBodyCallback { (flag, response, emitter) -> Bool in
// 全局, 所有請求都會經過這裡
// 可以在這裡根據統一的字段去判讀code什麼的是成功
// 如果不成功可以抛出異常,最後會在onError或者onEmpty中回調
// 可以根據使用者自己業務邏輯處理
/**
* eg: 僞代碼(假設 code:0成功, 1000: 資料為空, 其他為錯誤)
* let baseResponse = jsonToModel(response)
* let code = baseResponse.getCode()
* if(code != 0){
* if(code == 1000){
* emmit.onError(AutoNetError.Empty)
* } else {
* emmit.onError(AutoNetError.Custom(code, baseResponse.getMessage))
* }
* return true
* }
**/
return false
}
使用
AutoNet.getInstance().createNet(BaseResponse<String>(), String())
.doGet()
.setDomainNameKey(domainNameKey: "test")
.setSuffixUrl(suffixUrl: "/user/test")
.start(handlerBefore: { (response, emmit) -> Bool in
let data: String? = response.getData()
if(data == nil){
emmit.onError(AutoNetError.EmptyError)
return true
}
emmit.onNext(data!)
return true
}, optLocalData: nil, onPregress: nil, onComplete: nil, onSuccess: { (entity) in
print("data = \(entity)")
}, onError: { (error) in
print("請求錯誤: \(error)")
}) {
print("請求資料為空")
}