最近牵舵,一個(gè)同事打算離職柒啤,聊到技術(shù)上倦挂,就順便說道一個(gè)話題:
AFN的底層原理你知道嗎?
恰好担巩,最近正好處于三個(gè)項(xiàng)目交接期方援、起步期,跟不同的后臺(tái)開發(fā)人員和接口約定打了交道涛癌,發(fā)現(xiàn)問題(坑犯戏,后臺(tái)開發(fā)不規(guī)范導(dǎo)致)還是很多的。
要講清這個(gè)問題拳话,首頁得了解1.AFN怎么請(qǐng)求的先匪?2.一個(gè)網(wǎng)絡(luò)請(qǐng)求是怎么構(gòu)成的?為什么我的網(wǎng)絡(luò)請(qǐng)求失敗,別人能成功呢弃衍?
1.關(guān)于問題一呀非,文章http://www.reibang.com/p/96f115bcd913里講解的很清楚
2.關(guān)于問題二,我們需要看一下這個(gè)[AFHTTPSessionManager manager] 里面有什么镜盯!
@property (readonly, nonatomic, strong, nullable) NSURL *baseURL;
@property (nonatomic, strong) AFHTTPRequestSerializer <AFURLRequestSerialization> * requestSerializer;
@property (nonatomic, strong) AFHTTPResponseSerializer <AFURLResponseSerialization> * responseSerializer;
我將它們定位一個(gè)網(wǎng)絡(luò)請(qǐng)求的三要素
基本的URL岸裙,請(qǐng)求序列化器,響應(yīng)序列化器
我們重點(diǎn)看:這個(gè)三個(gè)要素怎么生成一個(gè)request的對(duì)象的速缆!
如果你只會(huì)上面那個(gè)文章里面調(diào)用請(qǐng)求降允,那你一定還處于AFN的入門使用階段。
如果你還會(huì)配置時(shí)間艺糜、緩存等參數(shù)剧董,那你進(jìn)入了初級(jí)階段。
如果你知道倦踢,一個(gè)get請(qǐng)求與post請(qǐng)求在AFN里面怎么拼裝送滞,怎么生效的原理,那么恭喜你進(jìn)入中級(jí)階段辱挥,我也才剛剛悟道犁嗅,分享一下。
要素一:url
如果是get請(qǐng)求晤碘,那么生成request可能是這樣的
https://host/v4/store/searchAppList?jsonObj={"platform":"android","userName":"fengj","appId":"qweasdzxc"}
PS:注意褂微?= 這個(gè)兩種符號(hào)是帶出了參數(shù)。
參數(shù)體現(xiàn)在url里面园爷。
那么在生成最終的請(qǐng)求類型request時(shí)宠蚂,一定要看后面的參數(shù)樣式,因?yàn)闃邮讲粚?duì)就會(huì)導(dǎo)致請(qǐng)求失敗童社。
如下列這種get請(qǐng)求肯定失斍蟛蕖:
https://host/v4/store/searchAppList?=%7B%20%20%22jsonObj%22%20%3A%20%7B%20%20%20%20%22appId%22%20%3A%20%22qweasdzxc%22%2C%20%20%20%20%22platform%22%20%3A%20%22iphone%22%2C%20%20%20%20%22userName%22%20%3A%20%22fengj%22%20%20%7D%7D
(這里是AFN默認(rèn)使用了urlcode 也就是escape編碼了)
https://host/v4/store/searchAppList?={jsonObj:{"appId":"qweasdzxc","platform":"iphone","userName":"fengj"}
或者這種請(qǐng)求也是不對(duì)的
https://host/v4/store/searchAppList?jsonObj[BappId]=qweasdzxc&jsonObj[platform]=iphone&jsonObj[userName]=fengj
為什么會(huì)產(chǎn)生這種get類型的URL呢?
關(guān)鍵代碼在AFURLRequestSerialization.m 中這個(gè)方法(466行)中:
- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
withParameters:(id)parameters
error:(NSError *__autoreleasing *)error{
....
}
這個(gè)方法里面針對(duì)get請(qǐng)求進(jìn)行了url參數(shù)的拼接,和針對(duì)post請(qǐng)求的body中的Data數(shù)據(jù)進(jìn)行了處理呀癣,還有很關(guān)鍵的HTTPRequestHeaders 請(qǐng)求頭的配置美浦。
具體自己可以讀一下代碼。
這里告知一下我犯錯(cuò)誤的原因:參數(shù)parameters 不符合后臺(tái)的需求项栏,自然接口不通浦辨!
如: NSDictionary * dic = @{
@"appId":@"qweasdzxc",
@"userName":@"fengj",
@"platform":@"iphone",
};
NSString * jsonString = [NSDictionary convertToJSONData:dic];
requestArgumentDic = @{@"jsonObj":[jsonString description]
}.mutableCopy;
與 requestArgumentDic = @{@"jsonObj":@{
@"appId":@"qweasdzxc",
@"userName":@"fengj",
@"platform":@"iphone",
}
}.mutableCopy;
這兩種參數(shù)類型就是截然不同的:
在iOS的世界:一個(gè)是字典,key對(duì)應(yīng)的是jsonStr沼沈;另一個(gè)是字典套字典
在java開發(fā)(安卓與后臺(tái))的世界:第一個(gè)是一個(gè)key-object 健值-對(duì)象模型流酬,另一個(gè)就是Map形式純嵌套。
因?yàn)楹笈_(tái)的解開數(shù)據(jù)方式不一樣列另,會(huì)導(dǎo)致后臺(tái)不認(rèn)識(shí)你傳過來的數(shù)據(jù)
要素二: 上述要素一種牽扯的方法芽腾,其實(shí)就是requestSerializer的方法
他們是協(xié)議關(guān)系,具體關(guān)系访递,可以看這篇文章:http://www.reibang.com/p/96f115bcd913 介紹地很詳細(xì)晦嵌。
如這篇文章所說,上面這個(gè)方法拷姿,更多是處理request的參數(shù)序列化問題惭载。
仔細(xì)讀這個(gè)方法:
可以知道一個(gè)mutableRequest 有三個(gè)重要組成部分
1、HTTPRequestHeaders
2响巢、url
3描滔、parameters (get時(shí)是url的后綴,post 是HTTPBody中的NSData數(shù)據(jù))
如果這三個(gè)要素完全一致踪古,不可能出現(xiàn)安卓接口調(diào)通含长,而iOS不通的情況的。
我遇到的畸形案列:
某一后臺(tái)要的數(shù)據(jù)(post body中的數(shù)據(jù)):沒有進(jìn)行urlcode編碼(一般情況下:URl中參數(shù)有沒有urlcode編碼都能請(qǐng)求通過伏穆,而nsdata中數(shù)據(jù)不一樣拘泞,后臺(tái)拿到數(shù)據(jù)解析方式?jīng)Q定能否使用。)但是AFN框架默認(rèn)會(huì)進(jìn)行urlcode編碼(文件名:AFURLRequestSerialization.m枕扫,方法名:AFQueryStringFromParameters(NSDictionary *parameters)里面122行[pair URLEncodedStringValue])陪腌;
對(duì)應(yīng)解決方法如下:
AFHTTPRequestSerializer * requestSerializer = [AFHTTPRequestSerializer serializer];
[manager setRequestSerializer:requestSerializer];
[requestSerializer setQueryStringSerializationWithBlock:^NSString * _Nonnull(NSURLRequest * _Nonnull request, id _Nonnull parameters, NSError * _Nullable __autoreleasing * _Nullable error) {
return [NSDictionary convertToJSONData:parameters];
}];
手動(dòng)設(shè)置requestSerializer參數(shù)query的字符串模式
第二個(gè)犯錯(cuò)的案列 比較簡(jiǎn)單
HTTPRequestHeaders 必須設(shè)置對(duì),尤其是這兩個(gè)參數(shù) Content-Type 與Accept
1.請(qǐng)求參數(shù)的格式 (另一種格式application/x-www-form-urlencoded;charset=UTF-8 )
[requestSerializer setValue:@"application/json;charset=UTF-8" forHTTPHeaderField:@"Content-Type"];
2.返回參數(shù)的格式
[requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Accept"];