iOS開發之網路錯誤分層處理
在使用iOS的URL載入系統時,手機端和伺服器端端連線可能會出現各種各樣的錯誤,大致可以分為3種:
1、作業系統錯誤:資料包沒有到達指定的目標導致。這類錯誤iOS中用NSError物件包裝起來了,這類錯誤可以用Apple 提供的Reachability來檢測到。可能導致作業系統錯誤的原因:
1.1 沒有網路:如果裝置沒有資料網路連線,那麼連線很快會被 拒絕或者失敗。
1.2 無法路由到目標主機,裝置可能連線網路了,但是連線的目標可能處於隔離的網路中或者掉線狀態。
1.3 沒有應用監聽目標埠,客戶端把資料傳送到目的主機指定的埠號,如果伺服器沒有監聽這個埠號(TCP/UDP服務端需要監聽指定的埠號)或者需要連線的任務太多,則請求會被拒絕。
1.4 主機域名無法解析,域名的解析並不一定成功的(筆者公司某款APP第一次用的時候域名DNS解析就容易失敗)
1.5 主機域名錯誤,域名寫錯了肯定找不到目標伺服器的,我在正確域名tb.ataw.cn改為/tb.ataw1.cn則會報錯:
Error Domain=NSURLErrorDomain Code=-1003 “未能找到使用指定主機名的伺服器。” UserInfo={NSUnderlyingError=0x174448040 {Error Domain=kCFErrorDomainCFNetwork Code=-1003 “(null)” UserInfo={_kCFStreamErrorCodeKey=50331647, _kCFStreamErrorDomainKey=6147616992}}, NSErrorFailingURLStringKey=
2、HTTP錯誤:由HTTP請求、HTTP伺服器或者應用伺服器的問題造成,這種型別的錯誤通常通過HTTP響應頭的狀態碼傳送給客戶端。HTTP錯誤的型別和原因:
2.1 資訊性質的100級別,來自HTTP伺服器的資訊,表示請求的處理將會繼續,但是有警告(筆者目前還沒遇到過)
2.2 成功的200級別,表示請求成功了,但是返回的資料不同代表了不同的結果,例如204表示請求成功,但是不會向客戶端返回負載。
2.3 重定向需要的300級別,表示客戶端必須執行某個操作才能繼續請求,因為需要的資源已經移動了,URL載入系統會自動處理重定向而無需通知程式碼,如果需要自定義處理 重定向,應該是用非同步請求。
2.4客戶端錯誤的400級別,表示客戶端發出了伺服器無法處理的錯誤資料,需要注意你URL後面的路徑、請求的引數格式、請求頭的設定等,例如,我把正確路徑
{ URL: http://tb.ataw.cn/app/UserLogin1 } { status code: 404, headers {
Server=Microsoft-IIS/7.5;
Content-Type=text/html; charset=utf-8;
X-Powered-By=ASP.NET;
Date=Fri, 23 Sep 2016 06:41:27 GMT;
Content-Length=3431;
Cache-Control=private;
X-AspNet-Version=4.0.30319;
} }
2.5 下游錯誤的500級別,表示伺服器與下游伺服器之間出現了錯誤,客戶段就會收到500級別的錯誤,這時候通常都是後臺開發的事情了,移動端告知他們修改。
3、應用錯誤:應用產生的錯誤(這一層的錯誤是我們開發中必須打交道的,客戶端可以根據服務端返回負載中的狀態碼來進行業務邏輯處理),這些錯誤是執行在服務層之上的業務邏輯和應用造成的,這一層中的狀態碼是可以自定義的,所以需要和後臺人員溝通好以便不同情況好處理業務邏輯。常見,例如,服務端的程式碼異常(筆者公司這種問題還蠻多的),這種錯誤一般服務端人員會給返回給客戶端的負載狀態碼子段賦值500,例如,當我們登入成功時,後臺返回的負載中狀態碼為200,如果登陸賬號密碼錯誤,則後臺人員會返回一個不同的狀態碼。注意:這一層的狀態碼後臺人員是可以任意定義的,所以開發中一定要溝通好哪個狀態碼對應什麼狀態。
錯誤處理:下面這段程式碼你一定看的懂,程式碼塊中的3個引數error、response、data,當系統錯誤型別時error會有錯誤資訊,response、data都為空,當HTTP伺服器錯誤時,error、data為空,response裡面有錯誤的狀態碼,但是沒有錯誤具體資訊,如果前面兩種錯誤都沒有,則會到應用錯誤,這時候data才有資料。
NSURLSessionDataTask task = [session dataTaskWithRequest:request completionHandler:^(NSData _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
//1、系統錯誤攔截 如果有錯,則return
if (error) {
;
errorblock(error);
return;
}
//2、HTTP錯誤攔截
NSHTTPURLResponse respond = (NSHTTPURLResponse )response;
if ([respond statusCode] == 300) {
return;
}
else if ([respond statusCode] == 400)
{
return;
}
else if ([respond statusCode] == 500)
{
return;
}
if (data) {
//3、應用層錯誤攔截
//解析JSON 原始的
/*
NSJSONReadingMutableContainers = (1UL << 0),//生成Mutable 的array和dictonary
NSJSONReadingMutableLeaves = (1UL << 1),//告訴解析器生成字串
NSJSONReadingAllowFragments//告訴解析器 頂層不是array和dictionary
*/
NSDictionary *jsonDic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
NSLog(@"下發資料:%@",[jsonDic descriptionWithLocale:nil]);
//把JSON解析後的資料返回給呼叫者,回撥block
completionblock(jsonDic);
}
}];
note:系統層的錯誤可以通過Apple提供的Reachability 來檢測而不必傳送網路請求,如果每次請求之前都用Reachability來判斷,則會增加網路負載和延遲,如果要用其測試當前網路能否訪問指定主機,則需要開闢新的執行緒來執行,否則會阻塞主執行緒。
通過這3層錯誤一層層檢測,避免一些沒必要的操作,可以提高APP的使用者體驗。