離散式與集約式網絡框架
集約式:
每個請求都會走統一的入口,對外暴露了請求的 URL 和 Param 以及請求方式,入口一般都是通過單例
來實現。例如
HttpClient.getInstance().sendRequest(url,params,callback)
優點:
1、使用便捷,可以快速開發
缺點:
1、對每個請求的定製要求不夠,例如,現在有個新需求,請求新聞條目需要保存網絡緩存,但其他網絡請求不需要。那麼我們必須新開一個sendRequest()方法,其中加一個參數isCache。這種情況對後期業務擴展非常不友好。
離散式:
即每個網絡請求類都是一個對象,它的 URL 以及請求方式和響應方式 均不暴露給外部調用。只能內部通過 重載或實現協議
的方式來指定,例如ios中的YTKNetWork即是這種方式。思想是爲每一個請求編寫一個配置類,在該類中重寫接口(協議)中定義的方法返回該網絡請求需要的參數。
優點:
1、擴展性強
2、URL 以及請求和響應方式不暴露給外部,避免外部調用的時候寫錯,設想一下,使用集約式設計,我們所有的URL地址均寫在一個類似URLContants的文件中,那麼新增、修改、刪除url都需要修改該文件,大大提高了出錯風險。
3、可定製性強,可以爲每個請求指定請求的超時時間以及緩存的週期
缺點:
每個網絡請求都要配置一個類,業務豐富後類數量較多
好,有了簡單的概念瞭解後,我們進入正題,設計一套離散式的網絡框架
swift離散式網絡框架
1、框架性代碼HttpRestfulClient
核心類,封裝第三方網絡請求庫,暴露請求方式,是單例。我就將代碼完全粘進來了,保證同學能看得懂
//
// HttpRestfulClient.swift
// HelloIOS
//
// Created by zxg on 2018/10/29.
// Copyright © 2018年 zxg. All rights reserved.
//
import UIKit
import Alamofire
import SwiftyJSON
import HandyJSON
class HttpRestfulClient {
static let sharedInstance = HttpRestfulClient()
private init() {}
// let device_id: Int = 6096495334
// let iid: Int = 5034850950
//Demo
//這裏使用了逃逸閉包,因爲responseJson爲異步,所以當網絡請求結果回來後,事實上testRequest()方法已經執行完了。那麼
//傳入函數testRequest()的閉包是在testRequest()函數執行完後,纔要執行的,也就是說這個閉包已經逃逸到函數外部了。所以要加該註解
//swift3.0默認是非逃逸的
//弊端
//該方法拿到數據後,字節解析字段,破壞了封裝性。合理的做法應該是封裝成model,再調用閉包,把model給出去
public func testRequset<T:HandyJSON>(_ completionHandler: @escaping(_ dataFromNet:AnyObject)->(),_ protocol:BaseProtocol<T>){
// let params = ["device_id": device_id, "iid": iid]
// Alamofire.request("https://is.snssdk.com/search/suggest/homepage_suggest/?", method: .get, parameters params).responseString{
// (response) in
// if let value = response.result.value{
// print("value:",value5034850950)
// let json = JSON(value)
// print(json)
// guard json["message"] == "success" else {return}
//
// if let data = json["data"].dictionary{
// completionHandler(data["homepage_search_suggest"]!.string!)
// }
// let responseModel = BaseResponse<T>.deserialize(from: value)!
// print("model:",responseModel.data)
// completionHandler((responseModel.data as? AnyObject)!)
// }
// }
}
//網絡請求函數,參數固定,所有網絡請求參數放在netProtocol中,即使以後擴展
//也不需要改變接口
public func sendRequset<T:HandyJSON>(_ netProtocol:BaseProtocol<T>,_ competionHandler:@escaping(_ model:AnyObject?,_ error:NetError)->()){
var error:NetError = NetError.SUCCESS
Alamofire.request(netProtocol.getOpertion()!,
method: transformMethod(netProtocol.getMethod()),
parameters: netProtocol.getParams()).responseString{
(response) in
if let value = response.result.value{
print("value:",value)
let responseModel = BaseResponse<T>.deserialize(from: value)!
if(responseModel.message! != "success"){
error = NetError.DATA_ERROR
}
competionHandler(responseModel.data as? AnyObject,error)
}
}
}
//自定義NetMethod轉Alamofire.HTTPMethod,目的是對上層完全隱藏Alamofire,這樣即使換掉Alamofire框架
//上層也不需要改動
private func transformMethod(_ method:NetMethod)->HTTPMethod{
switch method {
case .GET:
return HTTPMethod.get
case .POST:
return HTTPMethod.post
default:
return HTTPMethod.get
}
}
enum NetError:Int{
case SUCCESS = 0;
case DATA_ERROR = 1;
}
enum NetMethod:Int{
case GET = 10;
case POST = 20;
}
}
框架性代碼BaseProtocol
該類作爲sendRequest()的核心參數,封裝網絡請求參數,業務層開發時,不同的網絡請求均要實現這樣一個類
//
// BaseProtocol.swift
// HelloIOS
//
// Created by zxg on 2018/10/29.
// Copyright © 2018年 zxg. All rights reserved.
//
import UIKit
import HandyJSON
class BaseProtocol<T:HandyJSON> {
//返回網絡請求參數
func getParams()->Dictionary<String, AnyObject>?{
return nil;
}
//返回網絡地址url
func getOpertion()->String?{
return nil
}
//返回請求方法
func getMethod()->HttpRestfulClient.NetMethod{
return HttpRestfulClient.NetMethod.GET
}
//以後可以增加接口
public required init(){}
}
框架性代碼BaseResponse
用於使用HandyJSON進行Json解析,HandyJSON和Gson很像,都是採用反射、泛型等技術進行json與model的映射,不需要手動解析每一個字段,這裏使用泛型,也是爲了外部在調用時,通過泛型將需要映射成的目標model類傳進來,sendRequest內部進行解析。其實也可以直接將jsonStr拋給netProtocol,讓解析response這個動作也離散式的分解到每一個protocol中。而封裝BaseResponse的目的是做一些通用邏輯,例如在進行Model轉換前,判斷message是否爲success。是success再進行model轉換否則拋出error
//
// BaseResponse.swift
// HelloIOS
//
// Created by zxg on 2018/10/31.
// Copyright © 2018年 zxg. All rights reserved.
//
import Foundation
import HandyJSON
class BaseResponse<T>:HandyJSON{
var message:String?
var data:T?
public required init(){}
}
業務性代碼
這裏我們站在業務端角度,使用一下該簡單框架,網絡請求的名字就叫TestNet吧
爲本次網絡請求配置Protocol類:TestNetProtocol
//
// TestNetProtocol.swift
// HelloIOS
//
// Created by zxg on 2018/11/1.
// Copyright © 2018年 zxg. All rights reserved.
//
import Foundation
import HandyJSON
class TestNetProtocol:BaseProtocol<TestNetResponse>{
var device_id:Int=0
var iid:Int=0
override func getParams()->Dictionary<String, AnyObject>?{
return ["device_id": device_id as AnyObject, "iid": iid as AnyObject];
}
override func getOpertion()->String?{
return "https://is.snssdk.com/search/suggest/homepage_suggest/?"
}
override func getMethod() -> HttpRestfulClient.NetMethod {
return HttpRestfulClient.NetMethod.GET
}
required init(){
super.init()
}
}
Response類
//
// TestNetResponse.swift
// HelloIOS
//
// Created by zxg on 2018/10/31.
// Copyright © 2018年 zxg. All rights reserved.
//
import Foundation
import HandyJSON
class TestNetResponse:HandyJSON{
var call_per_refresh:Int?
var homepage_search_suggest:String?
var suggest_words:[SuggestWord]?
required init(){}
}
class SuggestWord:HandyJSON{
var id:Int?
var or:String?
var word:String?
required init(){}
}
在Controller中調用
//測試訪問網絡
@IBAction func testNet(_ sender: Any) {
prot.device_id = 6096495334
prot.iid = 5034850950
print("testNetWork click")
HttpRestfulClient.sharedInstance.sendRequset(prot,{(model,error) in
if error != HttpRestfulClient.NetError.SUCCESS {
print("error")
return
}
if let data = model as? TestNetResponse{
self.updateUI(model: data)
}
})
}
private func updateUI(model:TestNetResponse){
self.tvNetData.text = model.homepage_search_suggest!
}
網絡返回的json:
testNetWork click
value: {"data":{"call_per_refresh":1,"homepage_search_suggest":"勞森 | 今晚中國女排直播5 | 古德洛克","suggest_words":[{"id":"6538744360526157064","or":"qcrs:65","word":"勞森"},{"id":"6605143180503422221","or":"qc:349 qcrs:15","word":"今晚中國女排直播5"},{"id":"6573947909807592707","or":"qcrs:66","word":"古德洛克"}]},"message":"success"}
後記
邏輯比較簡單,沒有處理緩存、header頭等邏輯,僅僅是爲了展示離散式網絡訪問思想的優點,以及練習下swift的泛型、閉包等技術。如果有時間,後期會豐富。