前言
測(cè)試階段蜂林,還未曾放到項(xiàng)目中使用叔磷,后續(xù)會(huì)繼續(xù)優(yōu)化調(diào)整,初始版本
環(huán)境
pod 'Moya', '14.0.0'
pod 'HandyJSON', '5.0.3-beta'
Xcode 13.2
用法
1碍遍、基本模板
Moya 在對(duì)于 API 的封裝是基于 enum定铜,通過(guò)對(duì)于枚舉不同端點(diǎn)的不同用法,生成請(qǐng)求雀久。
如果項(xiàng)目小可以只有一個(gè)API.swift宿稀, 如果項(xiàng)目比較大,可以分模塊赖捌,分成幾個(gè)API.swift
public enum HJApi {
case zen
case version([String: String])
case sendMsg(String)
case uploadHeadImage(parameters: [String:Any], imageDate:Data)
}
extension HJApi: TargetType {
///域名
public var baseURL: URL {
switch self {
case .version(_):
return URL(string: "www.abc.com")!
default:
return URL(string: "www.def.com")!
}
}
///請(qǐng)求地址放到這里
public var path: String {
switch self {
case .zen:
return "/abc/abcdef"
case .version(_):
return "/abc/abcdefghi"
case .sendMsg(let msg):
return "/abcd/abcdef/\(msg)"
case .uploadHeadImage(parameters: _, imageDate: _):
return "/file/user/upload.jhtml"
}
}
///接口的請(qǐng)求類型
public var method: Moya.Method {
switch self {
case .zen:
return .get
default:
return .post
}
}
///請(qǐng)求的參數(shù)在這里處理
public var task: Task {
switch self {
case .version(let parameters):
return .requestParameters(parameters: parameters, encoding: JSONEncoding.default)
case .uploadHeadImage(parameters: let parameters, imageDate: let imgDate):
let formData = MultipartFormData(provider: .data(imgDate), name: "file",
fileName: "hangge.png", mimeType: "image/png")
return .uploadCompositeMultipart([formData], urlParameters: parameters)
default:
return .requestPlain
}
}
public var validationType: ValidationType {
return .successCodes
}
// 用于單元測(cè)試
public var sampleData: Data {
return "{}".data(using: String.Encoding.utf8)!
}
public var headers: [String: String]? {
return [
"content-type": "application/json;charset=utf-8;",
"platform": "ios",
]
}
}
2.網(wǎng)絡(luò)請(qǐng)求初始化
/// 網(wǎng)絡(luò)請(qǐng)求發(fā)送的核心初始化方法祝沸,創(chuàng)建網(wǎng)絡(luò)請(qǐng)求對(duì)象
private let provider = MoyaProvider<MultiTarget>(endpointClosure: endpointClosure, requestClosure: requestClosure, plugins: [networkPlugin], trackInflights: false)
///超時(shí)時(shí)長(zhǎng)
private var requestTimeOut: Double = 30
/// 網(wǎng)絡(luò)請(qǐng)求的基本設(shè)置,這里可以拿到是具體的哪個(gè)網(wǎng)絡(luò)請(qǐng)求,可以在這里做一些設(shè)置
private let endpointClosure = {(target: TargetType) -> Endpoint in
let url = target.baseURL.absoluteString + target.path
var task = target.task
var endPoint = Endpoint(url: url,
sampleResponseClosure: { .networkResponse(200, target.sampleData) },
method: target.method,
task: task,
httpHeaderFields: target.headers)
if let apiTarget = target as? MultiTarget,
let tar = apiTarget.target as? HJApi {
switch tar {
case .zen:
requestTimeOut = 20
return endPoint
default:
return endPoint
}
}
return endPoint
}
/// 網(wǎng)絡(luò)請(qǐng)求的設(shè)置
private let requestClosure = { (endpoint: Endpoint, done: MoyaProvider.RequestResultClosure) in
do {
var request = try endpoint.urlRequest()
// 設(shè)置請(qǐng)求時(shí)長(zhǎng)
request.timeoutInterval = requestTimeOut
// 打印請(qǐng)求參數(shù)
if let requestData = request.httpBody {
print("請(qǐng)求的url:\(request.url!)" + "\n" + "\(request.httpMethod ?? "")" + "發(fā)送參數(shù)" + "\(String(data: request.httpBody!, encoding: String.Encoding.utf8) ?? "")")
} else {
print("請(qǐng)求的url:\(request.url!)" + "\(String(describing: request.httpMethod))")
}
if let header = request.allHTTPHeaderFields {
print("請(qǐng)求頭內(nèi)容\(header)")
}
done(.success(request))
} catch {
done(.failure(MoyaError.underlying(error, nil)))
}
}
/// NetworkActivityPlugin插件用來(lái)監(jiān)聽網(wǎng)絡(luò)請(qǐng)求越庇,界面上做相應(yīng)的展示
/// 但這里我沒怎么用這個(gè)罩锐。。卤唉。 loading的邏輯直接放在網(wǎng)絡(luò)處理里面了
private let networkPlugin = NetworkActivityPlugin.init { changeType, _ in
print("networkPlugin \(changeType)")
// targetType 是當(dāng)前請(qǐng)求的基本信息
switch changeType {
case .began:
print("開始請(qǐng)求網(wǎng)絡(luò)")
case .ended:
print("結(jié)束")
}
}
///返回?cái)?shù)據(jù)
struct myResponseData: HandyJSON {
var isSuccess: Bool?
var code: String?
var message: String?
var data: String?
}
3. 網(wǎng)絡(luò)請(qǐng)求封裝
此處是返回NetWork網(wǎng)絡(luò)請(qǐng)求封裝
public class NetWork: NSObject {
}
在NETWork 里面的返回單個(gè)model和數(shù)組model以及字符串的網(wǎng)絡(luò)請(qǐng)求封裝涩惑,
///返回單 model 網(wǎng)絡(luò)請(qǐng)求
public class func request<T:HandyJSON>(target: TargetType,
modelType: T.Type,
successBlock: @escaping (_ code: String, _ model: T?, _ msg:String) -> Void,
failureBlock:@escaping (_ code: String, _ msg:String) -> Void){
provider.request(MultiTarget(target)) { result in
switch result {
case let .success(response):
if let json = try? response.mapJSON() {
responseData(json, { code, result, msg in
return successBlock(code, modelType.deserialize(from: result), msg)
}, failureBlock)
} else {
return failureBlock("-1", "返回?cái)?shù)據(jù)獲取失敗")
}
case let .failure(error):
print("failure\(error.localizedDescription)")
return failureBlock("-1", msgNetError)
}
}
}
返回?cái)?shù)組 model 網(wǎng)絡(luò)請(qǐng)求
///返回?cái)?shù)組 model 網(wǎng)絡(luò)請(qǐng)求
public class func request<T:HandyJSON>(target: TargetType,
modelTypes: [T].Type,
successBlock: @escaping (_ code: String, _ models: [T?], _ msg: String) -> Void,
failureBlock:@escaping (_ code: String, _ msg:String) -> Void){
provider.request(MultiTarget(target)) { result in
switch result {
case let .success(response):
if let json = try? response.mapJSON() {
responseData(json, { code, result, msg in
return successBlock(code, modelTypes.deserialize(from: result) ?? [], msg)
}, failureBlock)
} else {
return failureBlock("-1", "返回?cái)?shù)據(jù)獲取失敗")
}
case let .failure(error):
print("failure\(error.localizedDescription)")
return failureBlock("-1", msgNetError)
}
}
}
返回字符串 網(wǎng)絡(luò)請(qǐng)求
///返回字符串 網(wǎng)絡(luò)請(qǐng)求
public class func request(target: TargetType,
successBlock: @escaping (_ code: String, _ result: String, _msg: String) -> Void,
failureBlock:@escaping (_ code: String, _ msg:String) -> Void){
provider.request(MultiTarget(target)) { result in
switch result {
case let .success(response):
if let json = try? response.mapJSON() {
responseData(json, { code, result, msg in
return successBlock(code, result, msg)
}, failureBlock)
} else {
return failureBlock("-1", "返回?cái)?shù)據(jù)獲取失敗")
}
case let .failure(error):
print("failure\(error.localizedDescription)")
return failureBlock("-1", msgNetError)
}
}
}
數(shù)據(jù)解析封裝
///數(shù)據(jù)處理
class func responseData(
_ data: Any,
_ successBlock: @escaping (_ code: String, _ result: String, _ msg:String) -> Void,
_ failureBlock:@escaping (_ code: String, _ msg:String) -> Void) {
if let obj = JSONDeserializer<myResponseData>.deserializeFrom(dict: data as? [String:Any]) {
let message = obj.message ?? msgNetError
guard let code = obj.code, !code.isEmpty else {
return failureBlock("-1", message)
}
if "201" == code {
return failureBlock(code, message)
}
if "200" == code {
guard let dataEncode:String = obj.data, !dataEncode.isEmpty else {
return successBlock(code, "", message)
}
DDLogInfo("\n<數(shù)據(jù)解析結(jié)果>:\n\(String(describing: result))")
successBlock(code, result ?? "", message)
}else{
return failureBlock(code, message)
}
}else{
return failureBlock("-1", msgNetError)
}
}
3.網(wǎng)絡(luò)請(qǐng)求:舉個(gè)栗子??吧
model
struct HJVersionUpdateModel: HandyJSON {
var versionUpgradeId: String?
var content: String?
var upgradeType: String?
var downLoadUrl: String?
var createTime: String?
var updateTime: String?
}
網(wǎng)絡(luò)請(qǐng)求, 在這只需要傳參就好了桑驱,請(qǐng)求方式竭恬,請(qǐng)求鏈接跛蛋,已經(jīng)在API.swift處理過(guò)了
let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? ""
let parameters = ["appType":"ios", "version": version]
NetWork.request(target: HJApi.version(parameters),
modelType: HJVersionUpdateModel.self) { code, model, msg in
} failureBlock:nil}
遇到的問題:
1、post請(qǐng)求status: 400痊硕、405
在post的task 中赊级,使用了.requestParameters(parameters: par, encoding: URLEncoding.default)
問題原因:encoding問題
如果是 POST請(qǐng)求為 JSONEncoding.default
如果是 GET請(qǐng)求為 URLEncoding.default 或者 task設(shè)置 .requestPlain
解決方法借鑒自:swift 框架 moya post 請(qǐng)求遇到的坑
public var task: Task {
switch self {
case .version(let parameters):
return .requestParameters(parameters: parameters, encoding: JSONEncoding.default)
default:
//get請(qǐng)求一下兩種均可,建議第二種
//return .requestParameters(parameters: [:], encoding: URLEncoding.default)
return .requestPlain
}
}
此處僅做筆記岔绸,如有不足理逊,請(qǐng)各位大佬指出
demo 傳送門
demo鏈接??https://gitee.com/hcapp/hjnet.git