Server: Ubunta with nodejs express and nginx proxy.
When using my android app everything is working fine.
When using my iOS app i get:
"error calling GET on /district Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo={NSUnderlyingError=0x1c0458db0 {Error Domain=kCFErrorDomainCFNetwork Code=-1001 "(null)" UserInfo={_kCFStreamErrorCodeKey=-2102, _kCFStreamErrorDomainKey=4}}, NSErrorFailingURLStringKey=http://xxx.xxx.xxx.xxx/api/district, NSErrorFailingURLKey=http://xxx.xxx.xxx.xxx/api/district, _kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-2102, NSLocalizedDescription=The request timed out.}"
This error only happens when i do GET requests. I can login(POST) and add markers to my map etc. It all works. But getting data through get requests doesnt.
I think the the problem has to do with iOS having a 30sec timeout/keep alive on devices over iOS 6 or 7. It automatically sets a header to keep alive for 30 sec.
I had similar problems when working on my mac localhost server. But i fixed it by sending back a header with res.set("Connection", "close"); in my nodejs routes back to iOS. Like this:
nodejs districtRoutes.js
router.get('/api/district', passport.authenticate('jwt', { session:false }), function(req, res, next) {
log.info("inside getting districts");
District.find({}, function(err, district) {
if (err){
res.set("Connection", "close");
log.info("error getting districts");
res.status(404).json({message:"no districts found" + err});
res.end();
}else{
res.set("Connection", "close");
log.info("success getting districts");
res.json(district);
res.end();
}
});
});
swift iOS app. Inside httpRequester helper class
func getRequest (urlPath: String, body: [String:String], success: @escaping (Data, HTTPURLResponse) -> ()) {
let token: String! = KeychainWrapper.standard.string(forKey: "token")
//check if url is a proper URL string
guard let url = URL(string: baseUrl+urlPath) else {
print("Error: cannot create URL")
return
}
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "GET"
urlRequest.addValue("JWT " + token, forHTTPHeaderField: "Authorization")
//urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
//urlRequest.addValue("application/json", forHTTPHeaderField: "Accept")
let jsonData: Data
do {
jsonData = try JSONSerialization.data(withJSONObject: body)
urlRequest.httpBody = jsonData
} catch {
print("Error: cannot create JSON from body")
return
}
let task = URLSession.shared.dataTask(with: urlRequest) { (data: Data?, response: URLResponse?, error: Error?) in
guard error == nil else {
if let httpResponse = response as? HTTPURLResponse {
self.errorHandling(response: httpResponse)
}
print("error calling GET on /" + urlPath)
print(error!)
return
}
guard let responseData = data else {
print("Error: did not receive any data")
return
}
let httpResponse = response as! HTTPURLResponse
success(responseData, httpResponse)
}
task.resume()
}
I have the same code on my current ubunta server and as said, android works fine. So does post requests on iOS but not GET requests. The problem appears on booth wifi and 4g connection on iOS devices.
Let me know if there is anything else you need from me to help solve this problem.
Thanks!
A user receives the following error on sync: Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." Root Cause: This occurs when the Offline application was placed in the background or lost connection during sync.
NSURLErrorDomain error -1012. You might see this error message if you are running an outdated version of the NetUpdate application on your Mac. To resolve the issue, simply download and install the latest version of NetUpdate. Now, restart your computer and NetUpdate should work again as expected.
Truly, the 'The request timed out' error could be due to an iOS-related bug. If you face a similar predicament, there are two things you can do; either downgrade/undo the iOS update or install for a new bug-free update (go to Settings > General > Software Update > Download and Install).
The solution was to not send body with a GET request. I knew it did not follow the request pattern for GET. Thought it was possible.
It was bad project planning on my part. One of my first own projects as a developer. All identifying information that is not secret should be kept inside the token. So when sending get requests the header with token has all the information needed to filter what data is sent back to the user.
Good luck and hope it helps!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With