我一直在努力解决HTTP超时问题。 经过一个多月的调查,我很确定这是由HTTP持久连接错误造成的。 详情如下:
NSURLConnection
。 keep alive
错误,但我的是一个不同的问题。 更具体地说,该错误导致NSURLErrorNetworkConnectionLost
但我的错误是NSURLErrorTimedOut
。 但是,我不确定我的问题是否是由iOS 8的另一个bug引起的。 NSURLErrorTimedOut
,以及所有跟随(不能太远离最后一个重用持久连接)请求会导致NSURLErrorTimedOut
。 NSURLErrorTimedOut
。 从解决方法,我们可以看到所有这些工作,因为他们导致不良的持久连接被删除,并创build一个新的持久连接。 我的问题:
NSURLConnection
不重用当前的持续连接,但创build一个新的,所以我可以解决这个问题后,我检测到我的代码? 我通过使用CFNetwork
并直接控制Connection
标题成功缓解了iOS 8上的这个问题。 但是,iOS9上这个问题似乎变得更糟了。
因为我希望苹果能够在iOS 9上修复它,所以我终于开了一个雷达: http : //www.openradar.me/22770738 。
如果你也遇到这个问题,请复制我的雷达,或者更好的是,如果你有一个更可靠的重现样本,你可以自己发射雷达。
经过2周的研究,我可以回答问题3和4:
nginx
的持久连接超时在服务器上设置为5秒,这不应该是原因。 服务器工程师发现这些超时请求实际上是正常接收和响应的。 所以这更可能是一个客户端问题。 由于我有一个最小的可重复的代码来排除我的代码作为原因,原因应该是在iOS中。 CFNetwork
。 系统会覆盖更高级别的API,如NSURLConnection
或NSURLSession
的Connection
头。 同样的问题在这里,iOS只是试图在服务器放弃它之后重新使用连接。
大约两年前,我转而使用CFNetwork来解决这个问题,但是最近我发现用CFNetwork API实现SSL固定是不可能的。 所以现在我正在考虑回到NSURLSession。
经过一番挖掘,我发现系统不会重用NSURLSession
的连接,所以在一段时间内创建新会话应该可以解决问题。
但是我也发现(至少在macOS上):NSURLSession所做的每个连接持续时间可以持续180秒,并且该连接没有被释放或重置会话关闭,所以您可能需要实现一些缓存机制以避免创建大量的连接在同一时间。
这是我目前使用的简单机制:
@interface HTTPSession : NSObject @property (nonatomic, strong) NSURLSession * urlSession; @property (nonatomic, assign) CFTimeInterval flushTime; @end + (NSURLSession *)reuseOrCreateSession { static NSMutableArray<HTTPSession *> * sessions = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sessions = [NSMutableArray<HTTPSession *> array]; }); const CFTimeInterval serverTimeoutSeconds = 10; const CFTimeInterval systemTimeoutSeconds = 40; CFTimeInterval now = CFAbsoluteTimeGetCurrent(); HTTPSession * resultSession = nil; for (HTTPSession * session in sessions) { CFTimeInterval lifeTime = now - session.flushTime; if (lifeTime < serverTimeoutSeconds) { resultSession = session; break; } if (lifeTime > systemTimeoutSeconds) { resultSession = session; resultSession.flushTime = now; break; } } if (!resultSession) { resultSession = [HTTPSession new]; NSURLSession * session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]]; // setup session resultSession.urlSession = session; resultSession.flushTime = now; [sessions addObject:resultSession]; } return resultSession.urlSession; }
如果您将时间戳添加到所有请求URL? 我认为这将使每个请求独特,也许iOS会建立新的连接,每次你发送请求(我不知道,需要尝试)