Post Method Error : "The request timed out." - Swift - swift

I am sending data to api using the post method. But while working in advance, I have now moved my server to the windows sdd server and started to get the problem I wrote below all the time. While working on Similator, it doesn't work when I try it on my physical phone, I get this problem. What is the problem? A situation related to the firewall? Because I started to get this problem after moving the server. Or another problem?
NSErrorFailingURLStringKey=....php, NSErrorFailingURLKey=....php,
_kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-2102, NSLocalizedDescription=The request timed out.}
#objc func veriGonder() {
let url = NSURL(string: "...php")
var request = URLRequest(url: url! as URL)
request.httpMethod = "POST"
...
dataString = dataString + "&formCLASSNAMESTARIH\(verıTURUSTarih)"
dataString = dataString + "&formCLASSNAMESZAMAN\(verıTURUsZaman)"
...
let dataD = dataString.data(using: .utf8)
do {
let uploadJob = URLSession.shared.uploadTask(with: request, from: dataD)
{
data, response, error in
...
}

Here as the error specifies your request timed out. So to fix this either you need to increase the timeout interval or increase the server response interval from server-side. So, if it's the first option here's the code you need:
request.timeoutInterval = 100 // increase this to your desired value.

Related

Can timeout function be added when getting a string from a URL?

Sometimes I fetch information from a specific site.
But when the response is slow I would like to add a timeout function. I would like to know how.
Can I add a timeout function to the code below?
html = try String(contentsOf: url, encoding: String.Encoding.ascii)
You are not really supposed to use init(contentsOf:encoding:) to read from a remote URL. This initialiser is synchronous so while it is doing that your app's UI will freeze and the user won't be able to do anything, as you may have noticed.
You are supposed to use URLSession and URLRequest to fetch data from remote URLs. They are asynchronous so you get your data in a completion handler.
You can set a timeout in seconds when you create the URLRequest, and you will get an NSError in the completion handler if it timed out (among other reasons).
var request = URLRequest(url: URL(string: "https://example.com")!,timeoutInterval: 10)
request.addValue("text/plain", forHTTPHeaderField: "Content-Type")
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else {
print(String(describing: error))
return
}
let result = String(data: data, encoding: .ascii)
// do something with result
}
task.resume()

pho.to API Request Failing in Swift

Im currently trying to work with the pho.to API in my iOS application. I am experimenting with making simple requests according to the documentation, however I cannot seem to get the request to go through successfully. Inside my API client file, I have this code:
let dataStr = """
<image_process_call>
<image_url>http://developers.pho.to/img/girl.jpg</image_url>
<methods_list>
<method order="1">
<name>desaturation</name>
</method>
<method order="2">
<name>caricature</name>
<params>type=1;crop_portrait=true</params>
</method>
</methods_list>
<thumb1_size>100</thumb1_size>
</image_process_call>
"""
let encodedStr = dataStr.replacingOccurrences(of: "\n", with: "").replacingOccurrences(of: " ", with: "")
let signData = encodedStr.hmac(key: key)
let urlStr = "https://opeapi.ws.pho.to/addtask/?app_id=\(appId)&key=\(key)&sign_data=\(signData)&data=\(encodedStr.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!))"
The HMAC encoding is being done according to this Stack Overflow post. Unfortunately when making a request to this URL using URLSession I get this response:
<?xml version=\"1.0\"?>\n<image_process_response><status>SecurityError</status><err_code>614</err_code><description>Error in POST parameters: one or more parameters (DATA , SIGN_DATA or APP_ID) are empty</description></image_process_response>
I feel like my issue is more related to actually forming the request rather than something specific to the API itself. I know my code is a little messy, however I was hoping that somebody could point me in the right direction in terms of making a request like this. Thanks!
As per their documentation you can see that data sent over from POST requests are in body (In cURL calls -d specifies the body of the request)
You are sending params/data in query, which the pho.to API doesn't accept, hence the error.
Here's a sample on how you can do:
let defaultSessionConfiguration = URLSessionConfiguration.default
let defaultSession = URLSession(configuration: defaultSessionConfiguration)
// Setup the request with URL
let url = URL(string: "https://opeapi.ws.pho.to/addtask")!
var urlRequest = URLRequest(url: url)
// Convert POST string parameters to data using UTF8 Encoding
let postData = yourXMLString.data(using: .utf8)
// Set the httpMethod and assign httpBody
urlRequest.httpMethod = "POST"
urlRequest.httpBody = postData
// Create dataTask
let dataTask = defaultSession.dataTask(with: urlRequest) { (data, response, error) in
// Handle your response here
}
// Fire the request
dataTask.resume()

Swift REST Request PUT Optional(502 Bad Gateway: Registered endpoint failed to handle the request.)

I'm trying to do a PUT request using Swift. In a REST client, when I try to do a REST request the following way:
In Body- x-www-form-urlencoded, I add vote=1 and with id being taken in the param for example: /user/:id, it works!
I try to do the same in Swift code, it does not work and I get responseString = Optional(502 Bad Gateway: Registered endpoint failed to handle the request.
Here is my code:
var baseURL = "http://<domain>/user"
let putURL = baseURL + "/\(id)"
print(putURL)
let request = NSMutableURLRequest(URL: NSURL(string: putURL)!)
request.HTTPMethod = "PUT"
let putString = "vote=1"
request.HTTPBody = putString.dataUsingEncoding(NSUTF8StringEncoding)
request.timeoutInterval = 1500
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
guard error == nil && data != nil else {
print("error=\(error)")
return
}
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("responseString = \(responseString)")
}
task.resume()
You forgot to set the content type, e.g.
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
Without that, the server won't know what to do with the blob of random data that you just sent it.
I'm not saying that this is necessarily the only problem, but it is definitely a problem, and one big enough to cause the error you're seeing.

NSURLConnection response returns 500 Status Code

I am trying to connect to a local node.js server setup and authenticate the user. I keep getting the 500 status code and can't figure out what I am missing.
I have tried hitting the server with these credentials from a web browser, and it works as expected.
Note: I do understand I have to use the NSURLSession instead of NSURLConnection, but for now, I need to get this to work.
Here is my code,
func signInUserWithDetails(userName:String,userPassword:String,serverURL:NSURL) {
let credDic :[String:String]=["user[name]":userName,
"user[password]":userPassword ]
self.httpMethod="PUT"
self.httpPath="/account"
self.expectedStatusCode=201
self.actualStatusCode=NSNotFound
self.requestUniqueIdentifier = NSUUID().UUIDString
let urlComponents = NSURLComponents(URL: serverURL, resolvingAgainstBaseURL: false)!
urlComponents.path = httpPath
let formedURL = urlComponents.URL!
var requestOrg = NSMutableURLRequest(URL: formedURL)
requestOrg.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
requestOrg.addValue("application/json", forHTTPHeaderField: "Accept")
requestOrg.HTTPMethod=self.httpMethod!
print(requestOrg.allHTTPHeaderFields) // Output 1
do{
let theJSONData = try NSJSONSerialization.dataWithJSONObject(credDic,options: NSJSONWritingOptions.PrettyPrinted)
let theJSONText = NSString(data: theJSONData,encoding: NSASCIIStringEncoding)
requestOrg.HTTPBody = theJSONData;
let tempD=try NSJSONSerialization.JSONObjectWithData(requestOrg.HTTPBody!, options: []) as? [String:String]
print("\(tempD)") //Output 2
}catch let error as NSError {
print(error)
}
connection = NSURLConnection(request: requestOrg, delegate: self, startImmediately: true)!
}
And I am just printing out the response with this,
func connection(didReceiveResponse: NSURLConnection, didReceiveResponse response: NSURLResponse) {
print("----------------------didReceiveResponse")
self.response=response
print("Response Received:"+"\(self.response)")
let urlResponse:NSHTTPURLResponse = response as! NSHTTPURLResponse
let responseCode=urlResponse.statusCode
self.actualStatusCode=responseCode
}
And the result I get is
Optional(["Accept": "application/json", "Content-Type": "application/x-www-form-urlencoded"])
Optional(["user[password]": "R", "user[name]": "R"])
----------------------didReceiveResponse
Response Received:Optional(<NSHTTPURLResponse: 0x7faba269d440> { URL: http://localhost:3000/account } { status code: 500, headers {
Connection = "keep-alive";
"Content-Length" = 1464;
"Content-Type" = "application/json";
Date = "Sat, 26 Dec 2015 08:34:45 GMT";
"X-Powered-By" = Express;
} })
And the didReceiveData throws this error
{"error":{"message":"Cannot read property 'name' of undefined","stack":"TypeError: Cannot read property 'name' of undefined\n at Object.exports.signIn [as handle] ( .......
Status code 500 means, that the server could not process your data and ran into an internal error. This oftentimes is caused by improperly encoded HTTP messages, where the server was unable to catch all possible errors.
When looking at your code, it becomes immediately apparent:
You are not sending a properly application/x-www-form-urlencoded encoded data to the server. This is likely the main cause of your problem. The other cause might be, that it's likely not a PUT but a POST method which is required to sign-in.
But before explaining how you encode your data properly, I would suggest to find out whether your server accepts JSON as content data (application/json). If so, properly encoding the data is much easier: having a JSON object (your variable credDic), simply convert it to JSON as UTF-8 in a NSData container. Then, get the length in bytes, set headers Content-Type and Content-Length accordingly.
I had a similar issue but after tried to include Content-Type using application/json, it was solved.
Example: request.addValue("application/json", forHTTPHeaderField: "Content-Type")
The client application gets an HTTP status code of 500 with the message "Internal Server Error" as a response for API calls. The 500 Internal Server error could be caused by an error during the execution of any policy within Edge or by an error on the target/backend server.
The HTTP status code 500 is a generic error response. It means that the server encountered an unexpected condition that prevented it from fulfilling the request. This error is usually returned by the server when no other error code is suitable

Alamofire - NSURLCache is not working?

I set my cache as below
var cacheSizeMemory = 20 * 1024 * 1024
var cacheSizeDisk = 100 * 1024 * 1024
var sharedCache = NSURLCache(memoryCapacity: cacheSizeMemory, diskCapacity: cacheSizeDisk, diskPath: "SOME_PATH")
NSURLCache.setSharedURLCache(sharedCache)
Create request with cache policy
var request = NSMutableURLRequest(URL: NSURL(string: "\(baseUrl!)\(path)")!, cachePolicy: .ReturnCacheDataElseLoad, timeoutInterval: timeout)
Make a request and get a response with following Cache-Control private, max-age=60
Then try to check the cache
var cachedResponse = NSURLCache.sharedURLCache().cachedResponseForRequest(urlRequest)
value is nil
Any thoughts?
I was able to manually cache pages by writing them to the sharedURLCache like this:
Alamofire.request(req)
.response {(request, res, data, error) in
let cachedURLResponse = NSCachedURLResponse(response: res!, data: (data as NSData), userInfo: nil, storagePolicy: .Allowed)
NSURLCache.sharedURLCache().storeCachedResponse(cachedURLResponse, forRequest: request)
}
NSURLCache seems to respect the headers sent by the server, even if you configure the opposite everywhere else in your code.
The Wikipedia API, for example, sends
Cache-control: private, must-revalidate, max-age=0
Which translates to: Must revalidate after 0 seconds.
So NSURLCache says: “OK, I won’t cache anything.”
But by manually saving the response to the cache, it works. At least on iOS 8.2.
Almost lost my mind on this one. :)
I ended up manually adding Cache-Control as private in the header of my request and it now works. Don't even need to manually check the cache, Alamofire does it for you
let cachePolicy: NSURLRequestCachePolicy = isReachable() ? .ReloadIgnoringLocalCacheData : .ReturnCacheDataElseLoad
var request = NSMutableURLRequest(URL: NSURL(string: "\(baseUrl!)\(path)")!, cachePolicy: cachePolicy, timeoutInterval: timeout)
request.addValue("private", forHTTPHeaderField: "Cache-Control")
var alamoRequest = Manager.sharedInstance.request(urlRequest)
I found that URLCache does not save responses bigger than 5% (1/20) of capacity.
Default cache has memoryCapacity = 512000, it does not save to memory responses greater than 25600.
As a solution extend capacity
[Swift solution for resolving expiration of NSURLcache]
I think that main problem here is this: ReturnCacheDataElseLoad.
#arayax gave you the answer that will fix that probably, but my solution would be something like this:
Since I'm using Alamofire for Network requests I've set my configuration:
configuration.requestCachePolicy = .ReturnCacheDataElseLoad
And when I make request I do check internet connectivity, if it is true, then clear NSURLCache, so it will force Alamofire to make request on server and not from cache:
if Reachability.isConnectedToNetwork() == true {
ConfigService.cache.removeAllCachedResponses()
}
ConfigService.manager?.request(.GET, ...
I hope this will help, maybe for other type of problems with NSURLCache :)
For me it was Pragma →no-cache after removing this everything worked.
This is how I got the cache to work with Alamofire 4 and swift 3 (Semi full function for reference):
func getTheList(courseId : String )-> Void{
appConstants.sharedInstance.startLoading()
let TheURL = DEFAULT_APP_URL + "api/getMyList?Id="+ID
let urlString = NSURL(string: TheURL)
var mutableURLRequest = URLRequest(url: urlString! as URL)
mutableURLRequest.httpMethod = "GET"
mutableURLRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
mutableURLRequest.cachePolicy = NSURLRequest.CachePolicy.returnCacheDataElseLoad
Alamofire.request(mutableURLRequest)
.responseJSON
{.......