OC
中我们习惯使用AFNetworking
进行网络请求,而Alamofire
是同一团队开发的Swift版本,也是进行Swift项目开发必备的三方库。我们在使用AFNetWorking
网络请求时习惯对它进行再次封装,同样Alamofire
也需要我们的封装,以便让我们的代码更加精简。
封装需要解决的问题点:
- 网络环境可动态配置:开发环境、测试环境、生产环境等。
- 有可能存在多个服务,服务地址可设置。不同的请求可能使用不同的IP地址。
- 接口
API
单独存放,便于统一维护管理。 - 网络请求设置 Request Header。
- 请求成功与失败数据统一处理。
- 尽可能覆盖多种请求功能:登录、Get、Post、图片上传、下载等。
- 可配置的网络环境,使用
enum
来设置
/*
* 配置你的网络环境
*/
enum NetworkEnvironment{
case Development
case Test
case Distribution
}
- 定义多个私有属性,来存储不同的服务地址
// 登录服务
private var LogInBase_Url = ""
// 普通服务
private var ProgressBase_Url = ""
- 根据设置的开发环境不同,服务地址发生改变
let CurrentNetWork : NetworkEnvironment = .Test
private func judgeNetwork(network : NetworkEnvironment = CurrentNetWork){
if(network == .Development){
LogInBase_Url = "http://dev-***.com/common-portal/"
ProgressBase_Url = "http://dev-***.com:8080/isp-kongming/"
}else if(network == .Test){
LogInBase_Url = "http://test-***.com/common-portal/"
ProgressBase_Url = "http://test-***.com/isp-kongming/"
}else{
LogInBase_Url = "https://***.com/common-portal/"
ProgressBase_Url = "https://***.com/isp-kongming/"
}
}
- 封装网络请求。备注:我们使用
SwiftyJSON
三方库来解析Response
数据. 声明协议方法:
protocol NetworkToolDelegate {
// 登录请求
static func goToLogin(userName:String,password:String,completionHandler: @escaping(_ dict:[String : AnyObject]) -> (), errorHandler: @escaping(_ errorMsg : String) ->(), networkFailHandler: @escaping(_ error : Error) -> ())
//GET 请求
static func makeGetRequest(baseUrl : String,parameters : [String:AnyObject],successHandler: @escaping(_ json:JSON) ->(),errorMsgHandler : @escaping(_ errorMsg : String) ->(),networkFailHandler:@escaping(_ error : Error) -> ())
//POST 请求
static func makePostRequest(baseUrl : String,parameters : [String:Any],successHandler: @escaping(_ json:JSON) ->(),errorMsgHandler : @escaping(_ errorMsg : String) ->(),networkFailHandler:@escaping(_ error : Error) -> ())
/* 图片上传 请求
* imageData : 图片二进制数组
*/
static func upDataIamgeRequest(baseUrl : String,parameters : [String : String],imageArr : [UIImage],successHandler: @escaping(_ dict:JSON) ->(),errorMsgHandler : @escaping(_ errorMsg : String) -> (),networkFailHandler: @escaping(_ error:Error) -> ())
}
- 接口Api的统一维护,新建Swift文件,分清功能模块。
import Foundation
//MARK: - 反馈接口
//反馈提交
let cmd_custInsertUserFeedback = "cust/insertUserFeedback"
// 反馈 列表
let cmd_custSelectUserFeedback = "cust/selectUserFeedback"
//图片上传 反馈
let cmd_custImgUpdate = "cust/imgUpdate"
//MARK: - 内容营销
//栏目列表
let cmd_contentDictList = "content/dictList"
//产品列表
let cmd_contentUserProduct = "content/app/product"
//产品详情
let cmd_contentProductInfo = "content/product/info"
//往期回顾 列表
let cmd_contentProductHistoryList = "content/app/historyProduct"
//MARK: - 发票模块
//筛选条件
let cmd_GetInvoiceMenu = "GetInvoiceMenu"
//发票列表
let cmd_GetInvoiceList = "GetInvoiceList"
// 发票明细
let cmd_GetInvoiceInfo = "GetInvoiceInfo"
//合同信息
let cmd_GetInvoiceContractInfo = "GetInvoiceContractInfo"
//更新签收状态
let cmd_SaveInvoiceStatus = "SaveInvoiceStatus"
//上传回执信息
let cmd_SaveInvoiceUrl = "SaveInvoiceUrl"
//获取审批信息
let cmd_GetInvoiceLog = "GetInvoiceLog"
- 实现扩展方法
需要注意的点:- 这里有三个闭包:
completionHandler
:网络请求正常并且登录成功后调用。errorHandler
:网络请求正常,但是登录失败时候调用,errorMsg
是 服务返回的错误提示。networkFailHandler
: 网络请求失败或者服务异常调用。 -
@escaping()
: 逃逸闭包 - 方法 参数
encoding
有三种取值:
(1)URLEncoding
和URL相关的编码,有两种编码方式:直接拼接到URL中、通过request的httpBody传值
(2)JSONEncoding
把参数字典编码成JSONData后赋值给request的httpBody
(3)PropertyListEncoding
把参数字典编码成PlistData后赋值给request的httpBody - 获取cookie 的方式
- 这里有三个闭包:
let headerFields = response.response?.allHeaderFields as! [String : String]
let userCookie = headerFields["Set-Cookie"]`
最后的方法实现
extension NetworkToolDelegate{
static func goToLogin(userName:String,password:String,completionHandler: @escaping(_ dict:[String : AnyObject]) -> (), errorHandler: @escaping(_ errorMsg : String) ->(), networkFailHandler: @escaping(_ error : Error) -> ()){
// 调用 网络请求判断方法
judgeNetwork();
let url = LogInBase_Url + "common/portal/login"
let dict = ["username":userName,"password":password]
Alamofire.request(url, method: .get, parameters: dict, encoding:URLEncoding.default, headers: nil).responseJSON { (response) in
print(response)
// 网络连接或者服务错误的提示信息
guard response.result.isSuccess else
{ networkFailHandler(response.error!); return }
// 保存 cookies
let headerFields = response.response?.allHeaderFields as! [String : String]
let userCookie = headerFields["Set-Cookie"]
// print("userCookie>>>>>>\(userCookie ?? "0000000")")
UserDefaults.standard.set(userCookie, forKey: "userCookies")
UserDefaults.standard.synchronize()
if let value = response.result.value {
let json = JSON(value)
print(json)
// 请求成功 但是服务返回的报错信息
guard json["errorCode"].intValue == 0 else { errorHandler(json["errorMsg"].stringValue); return }
if let resultDict = json["result"].dictionary{
completionHandler(resultDict as [String : AnyObject])
}
}
}
}
}
这里登录接口单独拿出来是因为,我们需要登录接口获取cookie,在接下来的请求中,我们会把cookie放入 Request Header 发起请求。其他功能类似此方法,这里不再复写,具体的源码可参见我的Github。