在使用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=0x174****40 {Error Domain=kCFErrorDomainCFNetwork Code=-1003 "(null)" UserInfo={_kCFStreamErrorCodeKey=50331****47, _kCFStreamErrorDomainKey=614****92}}, NSErrorFailingURLStringKey=http://tb.ataw1.cn/app/UserLogin, NSErrorFailingURLKey=http://tb.ataw1.cn/app/UserLogin, _kCFStreamErrorDomainKey=614****92, _kCFStreamErrorCodeKey=50331****47, NSLocalizedDescription=未能找到使用指定主机名的服务器。}
2、HTTP错误:由HTTP请求、HTTP服务器或者应用服务器的问题造成,这种类型的错误通常通过HTTP响应头的状态码发送给客户端。HTTP错误的类型和原因:
2.1 信息性质的100级别,来自HTTP服务器的信息,表示请求的处理将会继续,但是有警告(笔者目前还没遇到过)
2.2 成功的200级别,表示请求成功了,但是返回的数据不同代表了不同的结果,例如204表示请求成功,但是不会向客户端返回负载。
2.3 重定向需要的300级别,表示客户端必须执行某个操作才能继续请求,因为需要的资源已经移动了,URL加载系统会自动处理重定向而无需通知代码,如果需要自定义处理 重定向,应该是用异步请求。
2.4客户端错误的400级别,表示客户端发出了服务器无法处理的错误数据,需要注意你URL后面的路径、请求的参数格式、请求头的设置等,例如,我把正确路径http://tb.ataw.cn/app/UserLogin 写成http://tb.ataw.cn/app/UserLogin1,则会报错:
<NSHTTPURLResponse: 0x17023ed40> { 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的用户体验