11

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";
}
m-jamshidzadeh
  • 121
  • 2
  • 6
  • What exactly is the error? – JAL Feb 24 '16 at 14:35
  • 1
    i have not any error in this code and this code works for me when i send a request to server and i get true response from server now i don't know how to send an audio FILE to server – m-jamshidzadeh Feb 24 '16 at 14:40
  • You need to be more specific about your problem. Have you tried any approach already? If you did and it didn't work then you should tell us what you tried so that it is possible to identify the issue. If, however, you did not make any attempt yourself then you should first Google "NSURLRequest attach file" – Andriy Gordiychuk Feb 24 '16 at 16:51
  • 1
    thanks for your result code i have this problem too and it's work for me – Mohammad Tazehkar Feb 29 '16 at 07:08
  • I tried download music from server in encoding format, and then write it back using filestream to save back to mp3. I think you can try it too, encode and send to server then write it using filestream – Lee Mar 09 '16 at 06:35

2 Answers2

4

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()

}
user3069232
  • 8,587
  • 7
  • 46
  • 87
2

Great answer above.. Here it's updated for Swift3:

 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()

}
ICL1901
  • 7,632
  • 14
  • 90
  • 138