swift, send file to server

m-jamshidzadeh picture m-jamshidzadeh · Feb 24, 2016 · Viewed 7.9k times · Source

I am learning swift and I send a request to the server with the code below. It works for simple request and I get response from the server. My problem is I can not send a file to server.

code :

let parameters = parameter

    let request = NSMutableURLRequest(URL: NSURL(string: requestUrl)!)
    let boundaryConstant = "-----Boundary+\(arc4random())\(arc4random())"


    let contentType = "multipart/form-data; boundary=" + boundaryConstant
    let boundaryStart = "--\(boundaryConstant)\r\n"
    let boundaryEnd = "--\(boundaryConstant)--\r\n"

    let body:NSMutableString = NSMutableString();

    for (key, value) in parameters {
        body.appendFormat(boundaryStart)
        body.appendFormat("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
        body.appendFormat("\(value)\r\n")
    }
    body.appendFormat(boundaryEnd)


    request.HTTPMethod = "POST"
    request.setValue(contentType, forHTTPHeaderField: "Content-Type")

    request.HTTPBody = body.dataUsingEncoding(NSUTF8StringEncoding)

    let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in

        guard error == nil && data != nil else {
            // check for fundamental networking error
            print("error=\(error)")
            return

        }


        if let httpStatus = response as? NSHTTPURLResponse where httpStatus.statusCode != 200 {           // check for http errors

            print("statusCode should be 200, but is \(httpStatus.statusCode)")
            print("response = \(response)")
        }


        self.responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)!
        print("MMMMMMMM \(self.responseString)")
        self.result = self.responseString.dataUsingEncoding(NSUTF8StringEncoding)! as NSData
        callback(self.responseString)

    }

    print("code start")
    task.resume()

result : i can post file to server by this code:

    override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    let request = createRequest()
    let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in
        if error != nil {
            // handle error here
            print(error)
            return
        }
        do {
            if let responseDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? NSDictionary {
                print("success == \(responseDictionary)")

            }
        } catch {
            print(error)

            let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
            print("responseString = \(responseString)")
        }
    }
    task.resume()


}

func createRequest () -> NSURLRequest {
    let param = []


    let boundary = generateBoundaryString()

    let url = NSURL(string: "URl")!
    let request = NSMutableURLRequest(URL: url)
    request.HTTPMethod = "POST"
    request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
    request.setValue("userValue", forHTTPHeaderField: "X-Client-user")
    request.setValue("passValue", forHTTPHeaderField: "X-Access-pass")


    //let path1 = NSBundle.mainBundle().pathForResource("voice", ofType: "png") as String!
    request.HTTPBody = createBodyWithParameters(param, filePathKey: "voice", paths: ["pathURl"], boundary: boundary)

    return request
}

func createBodyWithParameters(parameters: [String: String]?, filePathKey: String?, paths: [String]?, boundary: String) -> NSData {
    let body = NSMutableData()

    if parameters != nil {
        for (key, value) in parameters! {
            body.appendString("--\(boundary)\r\n")
            body.appendString("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
            body.appendString("\(value)\r\n")
        }
    }

    if paths != nil {
        for path in paths! {
            let url = NSURL(fileURLWithPath: path)
            let filename = url.lastPathComponent
            let data = NSData(contentsOfURL: url)!
            let mimetype = mimeTypeForPath(path)

            body.appendString("--\(boundary)\r\n")
            body.appendString("Content-Disposition: form-data; name=\"\(filePathKey!)\"; filename=\"\(filename!)\"\r\n")
            body.appendString("Content-Type: \(mimetype)\r\n\r\n")
            body.appendData(data)
            body.appendString("\r\n")
        }
    }

    body.appendString("--\(boundary)--\r\n")
    return body
}

func generateBoundaryString() -> String {
    return "Boundary-\(NSUUID().UUIDString)"
}


func mimeTypeForPath(path: String) -> String {
    let url = NSURL(fileURLWithPath: path)
    let pathExtension = url.pathExtension

    if let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension! as NSString, nil)?.takeRetainedValue() {
        if let mimetype = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)?.takeRetainedValue() {
            return mimetype as String
        }
    }
    return "application/octet-stream";
}

Answer

user3069232 picture user3069232 · Feb 24, 2016

As you read here, you should use NSURLSession for HTTP work, it far more flexible and powerful; and I think is destined to replace NSURLconnection...

https://www.objc.io/issues/5-ios7/from-nsurlconnection-to-nsurlsession/

Here is a example for you...

 func getMetaData(lePath:String, completion: (string: String?, error: ErrorType?) -> Void) {
// **** get_metadata ****
    let request = NSMutableURLRequest(URL: NSURL(string: "https://api.dropboxapi.com/2/files/get_metadata")!)
    let session = NSURLSession.sharedSession()
    request.HTTPMethod = "POST"

    request.addValue("Bearer ab-blah-blah", forHTTPHeaderField: "Authorization")
    request.addValue("application/json",forHTTPHeaderField: "Content-Type")
    request.addValue("path", forHTTPHeaderField: lePath)
    let cursor:NSDictionary? = ["path":lePath]
    do {
        let jsonData = try NSJSONSerialization.dataWithJSONObject(cursor!, options: [])
        request.HTTPBody = jsonData
        print("json ",jsonData)
    } catch {
        print("snafoo alert")
    }

    let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
        if let error = error {
            completion(string: nil, error: error)
            return
        }
        let strData = NSString(data: data!, encoding: NSUTF8StringEncoding)
        print("Body: \(strData)\n\n")
        do {
            let jsonResult = try NSJSONSerialization.JSONObjectWithData(data!, options:NSJSONReadingOptions.MutableContainers);
            self.jsonParser(jsonResult,field2file: "ignore")
            for (key, value) in self.parsedJson {
                print("key2 \(key) value2 \(value)")
            }

            completion(string: "", error: nil)
        } catch {
            completion(string: nil, error: error)
        }
    })
    task.resume()

}