Multipart-form data POST to upload image not working after boundary is added in Swift - ios

So I'm trying to do a multi-part post request in Swift using the following format:
user_id 3232424234
photo *PHOTO DATA*
I set up my request as shown at the bottom of this post and am getting the following error:
Optional(Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost." UserInfo={NSUnderlyingError=0x7f86235cfe40 {Error Domain=kCFErrorDomainCFNetwork Code=-1005 "(null)" UserInfo={_kCFStreamErrorCodeKey=-4, _kCFStreamErrorDomainKey=4}}, NSErrorFailingURLStringKey=ENDPOINTURL, NSErrorFailingURLKey=ENDPOINTURL, _kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-4, NSLocalizedDescription=The network connection was lost.})
This error seems extremely odd to me because I can make it go away by omitting the boundary requirements for the POST request, but the server than explodes with a 500 and lets the client know it omitted the boundary reqs, so yah. I am probably doing something wrong in Swift. Below is my code to make the request. Let me know if more info is needed, thx guru's of the world.
//Inputs in this scope are an "id" and a "photo"
let url = NSURL(string: "**URL**")
let boundary = NSUUID()
let request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "POST"
request.setValue("multipart/form-data; boundary=--\(boundary)", forHTTPHeaderField: "Content-Type")
let parameterBody:NSDictionary = [
"user_id": id,
]
let data:NSMutableData = NSMutableData()
parameterBody.enumerateKeysAndObjectsUsingBlock { (parameterKey: AnyObject, parameterValue: AnyObject, stop: UnsafeMutablePointer<ObjCBool>) -> Void in
data.appendData(NSString(string: "--\(boundary)\r\n").dataUsingEncoding(NSUTF8StringEncoding)!)
data.appendData(NSString(string: "\(parameterKey) \(parameterValue)\r\n").dataUsingEncoding(NSUTF8StringEncoding)!)
}
data.appendData(NSString(string: "--\(boundary)\r\n").dataUsingEncoding(NSUTF8StringEncoding)!)
data.appendData(NSString(string: "photo").dataUsingEncoding(NSUTF8StringEncoding)!)
data.appendData(photo.imageData as! NSData)
data.appendData(NSString(string: "--\(boundary)--\r\n").dataUsingEncoding(NSUTF8StringEncoding)!)
request.setValue("\(data.length)", forHTTPHeaderField: "Content-Length")
let task = NSURLSession.sharedSession().uploadTaskWithRequest(request, fromData: data) { (responseJSON: AnyObject?, response: NSURLResponse?, error: NSError?) -> Void in
//Here I handle the response and check for errors.
}
task.resume()

There are a ton of issues here:
The boundary should be NSUUID().UUIDString.
When you add the boundary to the Content-Type header, you should not add -- there.
The individual parts of the multipart request are not well-formed. For example, you're missing the Content-Disposition.
It's not critical, but you do not need to set Content-Length of the request. That's done for you.
I'd suggest you refer to this answer which provides example of how to form multipart request: Upload image with parameters in Swift. Or consider using Alamofire, which takes care of all of this for you.

Related

MessageExtension returned a NSURLErrorDomain when requesting the server

I'm developing iOS message extension to filter the unwanted message. The plugin needs a help from server to filter the message. However, the iOS returned the error NSURLErrorDomain while requesting the server.
Based on the official document, I have done the following steps:
I added Associated Domains capability with value: messagefilter:mydomain.io
I defined the key/value pair in Info.plist of Message Extension.
ILMessageFilterExtensionNetworkURL has value: https://mydomain.io/api/v1/sms
The code that I test the request as follows:
let url = URL(string: "https://mydomain.io/api/v1/sms")!
var request = URLRequest(url: url)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("you-value-goes-here", forHTTPHeaderField: "X-API-KEY")
let task = URLSession.shared.dataTask(with: request) { data, _, error in
if let data = data {
print(data)
} else if let error = error {
print("Http failed: \(error)")
}
}
task.resume()
From the stack trace, as far as I known, there is a problem with dns resolution. Why does this happened and how to fix this case?
[0] (null) "_kCFStreamErrorCodeKey" : Int32(-72000)
[1] (null) "NSUnderlyingError" : domain: "kCFErrorDomainCFNetwork" - code: 18446744073709550613
[2] (null) "_NSURLErrorFailingURLSessionTaskErrorKey" : "LocalDataTask <B496A974-7009-4FCE-BF45-FEC07BA1E8DF>.<1>"
[3] (null) "_NSURLErrorRelatedURLSessionTaskErrorKey" : 1 element
[4] (null) "NSLocalizedDescription" : "A server with the specified hostname could not be found."
Thanks

Alamofire post method in iOS Swift 4?

For getting push notification here i am sending postitem, token, like count and currentname using alamofire post method(pod version alamofire 4.5). I did not get any response when post method called and it does not show any errors.
I tried keeping breaking points in alamofire function, it call alamofire.requestion then it goes out function.
Here is the code tried to send post method to backend:
func postNotification(postItem: String, post: Post) {
print("Get token from post:::",post.token)
print(postItem)
let token = UserDefaults.standard.string(forKey: "token")
let headers: HTTPHeaders = ["Content-Type" :"application/x-www-form-urlencoded"]
let parameters : [String:Any] = ["count":post.likeCount!, "likedby":currentName, "postId=":postItem, "token": post.token!]
Alamofire.request("http://highavenue.co:9000/likesnotification/", method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: nil).responseJSON { (response:DataResponse<Any>) in
switch(response.result) {
case .success(_):
if let data = response.result.value{
print(data)
}
break
case .failure(_):
print(response.result.error as Any)
break
}
}
}
Getting console error like this
2018-07-10 14:21:07.980212+0530 HighAvenue[10584:4236493] Task <B5FC98AB-C3FE-
4D4F-9A93-72D3FFE35DF7>.<1> finished with error - code: -1001
Optional(Error Domain=NSURLErrorDomain Code=-1001 "The request timed out."
UserInfo={NSUnderlyingError=0x1c0e478f0 {Error Domain=kCFErrorDomainCFNetwork Code=-1001 "(null)" UserInfo={_kCFStreamErrorCodeKey=-2102, _kCFStreamErrorDomainKey=4}}, NSErrorFailingURLStringKey=http://highavenue.co:9000/likesnotification/, NSErrorFailingURLKey=http://highavenue.co:9000/likesnotification/, _kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-2102, NSLocalizedDescription=The request timed out.})
That is because you are not setting request time in your network call, by default your request time is a small interval, so please increase request timeout time. something like this,
let request = NSMutableURLRequest(url: URL(string: "")!)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.timeoutInterval = 120 // 120 secs
let values = ["key": "value"]
request.httpBody = try! JSONSerialization.data(withJSONObject: values, options: [])
Alamofire.request(request as! URLRequestConvertible).responseJSON {
response in
// do whatever you want here
}
Second mistake in your code is you are trying to access http url which are by default are not allowed so you have to by pass this security from your app, Please refer to this answer in order to remove this security layer from your app.
The resource could not be loaded because the App Transport Security policy requires the use of a secure connection

Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost

I am getting this error when using SwiftyBeaver logger, which tries to send data to the cloud via this code:
func sendToServerAsync(str: String?, complete: (ok: Bool, status: Int) -> ()) {
if let payload = str, let queue = self.queue {
// create operation queue which uses current serial queue of destination
let operationQueue = NSOperationQueue()
operationQueue.underlyingQueue = queue
let session = NSURLSession(configuration:
NSURLSessionConfiguration.defaultSessionConfiguration(),
delegate: nil, delegateQueue: operationQueue)
// assemble request
let request = NSMutableURLRequest(URL: serverURL)
request.HTTPMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
// basic auth header
let credentials = "\(appID):\(appSecret)".dataUsingEncoding(NSUTF8StringEncoding)!
let base64Credentials = credentials.base64EncodedStringWithOptions([])
request.setValue("Basic \(base64Credentials)", forHTTPHeaderField: "Authorization")
// POST parameters
let params = ["payload": payload]
do {
request.HTTPBody = try NSJSONSerialization.dataWithJSONObject(params, options: [])
} catch let error as NSError {
toNSLog("Error! Could not create JSON for server payload. \(error)")
}
//toNSLog("sending params: \(params)")
//toNSLog("\n\nbefore sendToServer on thread '\(threadName())'")
sendingInProgress = true
// send request async to server on destination queue
let task = session.dataTaskWithRequest(request) {
_, response, error in
var ok = false
var status = 0
//toNSLog("callback of sendToServer on thread '\(self.threadName())'")
if let error = error {
// an error did occur
self.toNSLog("Error! Could not send entries to server. \(error)")
} else {
if let response = response as? NSHTTPURLResponse {
status = response.statusCode
if status == 200 {
// all went well, entries were uploaded to server
ok = true
} else {
// status code was not 200
var msg = "Error! Sending entries to server failed "
msg += "with status code \(status)"
self.toNSLog(msg)
}
}
}
return complete(ok: ok, status: status)
}
task.resume()
}
}
The strange thing is it works for the first two or three log entries, and then stops due to the above error. I tried to reset content and settings on the simulator and reboot my simulator (as suggested in Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost.") but that just fixes it temporarily--after the first 2-3 log entries, it starts failing again.
I tried debugging this for hours with the creator of SwiftBeaver last night, but we couldn't get it to work. Seems like not many people are seeing this issue.
I tried removing my Wifi connection and reconnecting, but that didn't work either.
Any guidance on this would be much appreciated.
FYI, I'm using Swift 2 and XCode 7.3.
This is probably caused by HTTP keep-alive support being seriously buggy in the iOS simulator. See:
Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost."
for more details, but the short answer is to disable keep-alive on the server that you use when doing simulator testing, or better yet, add some logic that immediately retries the request if it sees that particular error.

Error Code=-1005 "The network connection was lost." in Swift while consuming Web Service

I'm working on a iOS project in Swift 2.0, which has Web service calls, these services are slow to respond and that is normal, can be up to 1 minute or a little more, when i call the service 70% of the time it answers with the error "the network connection was lost." The tests were conducted in both simulator and different phone devices and iPad and the result is the same. The network connection is strong and the same application was also created on Android and working properly almost 100% of the time.
The way I call services from any view is as follows:
#IBAction func contratarAct(sender: AnyObject) {
conexion.delegate = self
loadingView = MEXLoadingView(delegate: self, title: "Espere por favor", percent: false, view: self.view)
self.loadingView.showAnimated(true)
let url = urlServicios.urlBaseServicios + "/" + idSolicitud + "/" + idNoCliente + "/CONTRATO"
conexion.consultaServicioGET(url, httpMethod: "PUT")
}
And the method that is executed is as follows:
func consultaServicioGET(url : String, httpMethod : String ){
let urlString = url
let request = NSMutableURLRequest(URL: NSURL(string: urlString)!)
request.timeoutInterval = 540
request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalAndRemoteCacheData
request.addValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
var session = NSURLSession.sharedSession()
request.HTTPMethod = httpMethod
let urlconfig = NSURLSessionConfiguration.defaultSessionConfiguration()
urlconfig.timeoutIntervalForRequest = 540
urlconfig.timeoutIntervalForResource = 540
session = NSURLSession(configuration: urlconfig, delegate: self, delegateQueue: nil)
let task = session.dataTaskWithRequest(request , completionHandler: {
(data:NSData?, response:NSURLResponse?, error:NSError?) in
if error != nil {
let jsonError : NSDictionary = NSDictionary()
self.delegate?.respuestaServicioGET!(jsonError, mensaje: "\(error!.localizedDescription)")
return
}
let jsonString = NSString(data: data!,encoding: NSASCIIStringEncoding)
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
let json: NSDictionary = try! NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
if (json.isKindOfClass(NSDictionary) ){
self.delegate?.respuestaServicioGET!(json, mensaje: "OK")
}else{
let jsonError : NSDictionary = NSDictionary()
self.delegate?.respuestaServicioGET!(jsonError, mensaje: "ERROR")
}
})
task.resume()
}
the error displayed is:
error=Optional(Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost." UserInfo={NSUnderlyingError=0x7fbde5f51df0 {Error Domain=kCFErrorDomainCFNetwork Code=-1005 "(null)" UserInfo={_kCFStreamErrorCodeKey=-4, _kCFStreamErrorDomainKey=4}}, NSErrorFailingURLStringKey=https://particulares-gw-obparticularesmx-pre.appls.cto2.paas.gsnetcloud.com:443/OPB/57dadf7de4b0ac2e518de44a/57dadf7de4b06c6b04ef0dcf/CONTRATO, NSErrorFailingURLKey=https://particulares-gw-obparticularesmx-pre.appls.cto2.paas.gsnetcloud.com:443/OPB/57dadf7de4b0ac2e518de44a/57dadf7de4b06c6b04ef0dcf/CONTRATO, _kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-4, NSLocalizedDescription=The network connection was lost.})
I add some code like the following:
urlconfig.timeoutIntervalForRequest = 540
urlconfig.timeoutIntervalForResource = 540
Trying to get more "timeout" but this is not looks like a timeout.
I can not get out of this error for days, any help will be greatly appreciated. I'm desperate.
If you're expecting a socket to stay open for minutes at a time, you're in for a world of hurt. That might work on Wi-Fi, but on cellular, there's a high probability of the connection glitching because of tower switching or some other random event outside your control. When that happens, the connection drops, and there's really nothing your app can do about it.
This really needs to be fixed by changing the way the client requests data so that the responses can be more asynchronous. Specifically:
Make your request.
On the server side, immediately provide the client with a unique identifier for that request and close the connection.
Next, on the client side, periodically ask the server for its status.
If the connection times out, ask again.
If the server says that the results are not ready, wait a few seconds and ask again.
On the server side, when processing is completed, store the results along with the identifier in a persistent fashion (e.g. in a file or database)
When the client requests the results for that identifier, return the results if they are ready, or return a "not ready" error of some sort.
Have a periodic cron job or similar on the server side to clean up old data that has not yet been collected.
With that model, it doesn't matter if the connection to the server closes, because a subsequent request will get the data successfully.
I faced the same issue and I am attaching a screenshot of the resolution to show how I resolved the issue.
In my case, the issue was that the API requests are blocked from the server Sucuri/Cloudproxy (Or you can say firewall service). Disabling the firewall resolved the issue
I don't why but it's works when I add sleep before my request:
sleep(10000)
AF.request(ViewController.URL_SYSTEM+"/rest,get_profile", method: .post, parameters: params, encoding: JSONEncoding.default , headers: headers).responseJSON { (response) in
}
I faced this issue and spend more than 1 week to fix this. AND i just solved this issue by changing Wifi connection.

Swift: error when trying to communicate with web API

I am trying to build a really basic iOS app using Swift - this is my first time doing so. Whilst the majority of it has been really straight forward. I have had a total nightmare getting the app to talk to my API, or any site in general!
This is the code i'm using, and specifically the code which is erroring:
NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
println(NSString(data: data, encoding: NSUTF8StringEncoding))
})
it's the 'NSString(data: data, encoding: NSUTF8StringEncoding)' that errors
I've gone through as many tutorials as I can find, and they all return me the same problem. I get an error saying:
NSURLErrorDomain - code: 4294966291
I also get a 'EXC_BAD_INSTRUCTION' error with: EXC_1386_INVOP, sub code = 0x0 (which hasn't led me to a solution...
Which makes me think that I haven't done something right in my set up, or something should be turned on in my preferences, or something along those lines as opposed to my code...
this is my whole code:
var URL: NSURL = NSURL(string: "http://stackoverflow.com")
var request:NSMutableURLRequest = NSMutableURLRequest(URL:URL)
request.HTTPMethod = "POST"
var bodyData = "key1=value&key2=value&key3=value"
println(URL)
println(bodyData)
request.HTTPBody = bodyData.dataUsingEncoding(NSUTF8StringEncoding);
let queue:NSOperationQueue = NSOperationQueue()
NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
println(NSString(data: data, encoding: NSUTF8StringEncoding))
})
Update:
Using Rob's code, I know get an error printed:
sendAsynchronousRequest error: Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost." UserInfo=0x7beafcc0 {NSErrorFailingURLStringKey=http://stackoverflow.com, _kCFStreamErrorCodeKey=57, NSErrorFailingURLKey=http://stackoverflow.com, NSLocalizedDescription=The network connection was lost., _kCFStreamErrorDomainKey=1, NSUnderlyingError=0x7d154ca0 "The network connection was lost."}
It sounds like data is nil. Examine the contents of the error object, and it should give you an indication of why. Most likely, there's something wrong with the request, but unless we can reproduce the problem, it's hard to diagnose.
Anyway, if you want to perform the request with a little more diagnostic information (log error if there is a problem, log statusCode and response if status code was not 200, etc.):
NSURLConnection.sendAsynchronousRequest(request, queue: queue) {
response, data, error in
if data == nil {
println("sendAsynchronousRequest error: \(error)")
return
}
if let httpResponse = response as? NSHTTPURLResponse {
let statusCode = httpResponse.statusCode
if statusCode != 200 {
println("sendAsynchronousRequest status code = \(statusCode); response = \(response)")
}
}
println(NSString(data: data, encoding: NSUTF8StringEncoding))
}
In your revised question, you shared the resulting NSError, which reported -1005 (which, in retrospect, is the same as the 4294966291 error code you showed us earlier; the latter being the the unsigned integer representation of -1005). This error (as the description describes) is for NSURLErrorNetworkConnectionLost (which is kCFURLErrorNetworkConnectionLost), for which the documentation says, "Returned when a client or server connection is severed in the middle of an in-progress load."
Unfortunately, this error is used for a diverse array of issues, and as I'm unable to reproduce the error you describe, it's hard to diagnose.
One thing that is missing from the request is the specification of the Content-Type:
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
That wouldn't cause the problem you describe, but it's good practice to always inform the server of the type of the request.
I solved this, partly thanks to Rob's answers and general help - that was very useful.
The Key in the end though, was super simple and taken from this question: Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost."
I just had to restart the simulator. However I wouldn't have gotten there without the additional if data == nil {} statement.

Resources