NSURLErrorDomain的-1005错误
关于HTTP 1.1和HTTP长连接
HTTP 1.0中,默认进行的都是短连接。一个HTTP请求会产生一个TCP连接,请求结束后就会关闭这个TCP连接。而自HTTP 1.1开始,默认进行的都是长连接。在一个HTTP请求结束之后,客户端和服务端之间的TCP连接并不会立即断开,而是按照约定的Keep-Alive时长维持一定时间的连接状态。这样在下一次HTTP请求发生时,如果TCP连接还存在就会复用之前的TCP连接,省去重新建立TCP连接的时间。
iOS的-1005错误
我们的团队是在使用SDWebImage的时候遇到这个问题的,经搜索发现早在iOS 8时代就有人在使用AFNetworking的时候遇到这个问题:NSURLErrorDomain的-1005错误
1 | Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost." |
具体的原因参照这个回答的描述:NSURLRequest的实现有问题,在维持长连接的时候维持时长超过了服务器约定的时长,在第二次HTTP请求准备复用TCP连接的时候实际上连接已经被服务器断开了。
我没有去调研&测试NSURLRequest的实现是不是真的有问题,倒是觉得移动设备的一些极端网络情况可能的确会面临这样的问题。
那么接下来就是要解决这个问题。
由服务端解决这个问题
1. 提高服务器Keep-Alive时长至30秒以上
我在简书上也看到有人将Keep-Alive时长设置成了60秒,对应问题可以解决。
但是这个设置对于服务器是有风险的。延长Keep-Alive时长无疑会浪费服务器的性能,毕竟同时需要维持的连接数变多了。很多用户其实也不需要这么长时间的长连接。所以这个方案需要斟酌之后再确定要不要实行。
2. 针对iOS客户端禁用长连接
不同的服务器设置方法不一样,具体方法就不多说了。
这个方案的风险在于,抛弃了长连接会对HTTP请求的速度产生些许影响。
由客户端解决这个问题
1. 重新实现HTTP请求底层,降低客户端Keep-Alive时长
这是个大工程,我们需要写一个完备的底层,使客户端的Keep-Alive时长比服务端传回的时长短一些。这样的话就更低概率甚至不会出现服务端比客户端早断开TCP连接的情况。在出现长连接断开的情况下,底层也应该负责进行一次重试,再开一个新的TCP连接进行HTTP请求。
2. 由业务层或框架层重试HTTP请求
出现错误的时候重试一次HTTP请求就好。在框架或者业务代码里仍然用NSURLRequest实现请求,捕获到-1005错误的时候进行一次重试。虽然说总体用时会更长,但是正确的结果更加重要些。
SDWebImage里的问题
在SDWebImage中遇到此问题的现象:有些图片一旦请求失败一次就再也没法刷出来。
归根结底在于SDWebImage维护了一个failedURLs列表,请求失败的图片URL都会被加入到这个表中。下次请求的时候如果没有带上SDWebImageRetryFailed选项,SDWebImage就会自动忽略这些URL直接返回错误。
某些特殊的网络错误会被判定是网络连接问题,请求失败时SDWebImage不会将图片URL加入failedURLs列表。而这个特殊的网络错误列表里之前没有包含-1005错误,导致出现-1005错误后这些图片就再也不会被重加载。
好在2个月前(2017-1-6)有人提交了对应的修改:add a network error situation,我们的SDWebImage是太久没更新了才会遇到这个问题。
YYWebImage里的实现
参照YYWebImageOperation类的实现。
和SDWebImage实现不同的是:
- YYWebImage默认是不会记录URLInBlackList的,只有带上YYWebImageOptionIgnoreFailedURL选项,请求图片失败时才会把图片URL加入URLInBlackList。
- YYWebImage默认是会重试URLInBlackList的,必须带上YYWebImageOptionIgnoreFailedURL选项,才会忽略URLInBlackList中的图片URL。
介于以上原因,实际上按照默认行为使用YYWebImage时如果加载图片失败,下一次加载还是会重试的,所以不会导致图片一直刷不出的严重问题。
当然YYWebImage处理的网络连接问题列表里也没有包含-1005错误,所以我已经提了pull request。
总结
对于大部分团队来说,应该还是用客户端方案2来处理比较方便。
需要做的就是在客户端请求服务API和图片资源时,出现-1005错误就进行一次重试。
当然如果使用了以上图片库,记得更新下最新版或者手动加上对-1005错误的处理。