Upload image with multipart form-data iOS in Swift

前端 未结 7 1003
無奈伤痛
無奈伤痛 2020-11-27 13:08

i am having a problem with uploading image with multipart-form

here is my code i used from this answer

    var request = NSMutableURLRequest(URL: url         


        
相关标签:
7条回答
  • 2020-11-27 13:50

    No Need to use any library for upload images using multipart request.

    Swift 4.2

    func uploadImage(paramName: String, fileName: String, image: UIImage) {
        let url = URL(string: "http://api-host-name/v1/api/uploadfile/single")
    
        // generate boundary string using a unique per-app string
        let boundary = UUID().uuidString
    
        let session = URLSession.shared
    
        // Set the URLRequest to POST and to the specified URL
        var urlRequest = URLRequest(url: url!)
        urlRequest.httpMethod = "POST"
    
        // Set Content-Type Header to multipart/form-data, this is equivalent to submitting form data with file upload in a web browser
        // And the boundary is also set here
        urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
    
        var data = Data()
    
        // Add the image data to the raw http request data
        data.append("\r\n--\(boundary)\r\n".data(using: .utf8)!)
        data.append("Content-Disposition: form-data; name=\"\(paramName)\"; filename=\"\(fileName)\"\r\n".data(using: .utf8)!)
        data.append("Content-Type: image/png\r\n\r\n".data(using: .utf8)!)
        data.append(image.pngData()!)
    
        data.append("\r\n--\(boundary)--\r\n".data(using: .utf8)!)
    
        // Send a POST request to the URL, with the data we created earlier
        session.uploadTask(with: urlRequest, from: data, completionHandler: { responseData, response, error in
            if error == nil {
                let jsonData = try? JSONSerialization.jsonObject(with: responseData!, options: .allowFragments)
                if let json = jsonData as? [String: Any] {
                    print(json)
                }
            }
        }).resume()
    }
    

    If you have any header to add, you can add it via urlRequest.setValue method.

    Source: https://fluffy.es/upload-image-to-server/

    0 讨论(0)
  • 2020-11-27 13:50
    class func postMultiPartdata( postdatadictionary: [AnyHashable: Any], apikey: String, completion: @escaping (Any) -> () ) {
    
            if Utils().isConnectedToNetwork() == false
            {
                Utils().showMessage("Check internet")
                return
            }
    
            let strURL = "http://redspark.biz/dropp/api/\(apikey)"
    
            let url = URL(string: strURL)
            var urlRequest = URLRequest(url: url!)
    
            urlRequest.httpMethod = "POST"
    
            let body = NSMutableData();
            let boundary = "---------------------------14737809831466499882746641449"
            let contentType = "multipart/form-data; boundary=\(boundary)"
            urlRequest.addValue(contentType, forHTTPHeaderField: "Content-Type")
    
            for (key, value) in postdatadictionary {
    
                if(value is Data)
                {
                    let  TimeStamp = "\(Date().timeIntervalSince1970 * 1000)"
    
                    body.append("--\(boundary)\r\n".data(using: .utf8)!)
                    body.append("Content-Disposition: form-data; name=\"\(key)\"; filename=\"\(TimeStamp)\"\r\n".data(using:.utf8)!)
                    body.append("field_mobileinfo_image\r\n".data(using: .utf8)!)
    
                    body.append("--\(boundary)\r\n".data(using: .utf8)!)
                    body.append("Content-Disposition: form-data; name=\"files[field_mobileinfo_image]\"; filename=\"img.jpg\"\r\n".data(using: .utf8)!)
                    body.append("Content-Type: image/jpeg\r\n\r\n".data(using: .utf8)!)
    
    //                var imgData: Data? = nil
    //                if let aKey = value as? Data {
    //                    imgData = NSData(data: aKey) as Data
    //                }
    
                    body.append(value as! Data)
    
                }
                else
                {
                    if let anEncoding = "--\(boundary)\r\n".data(using: .utf8) {
                        body.append(anEncoding)
                    }
                    if let anEncoding = "Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n".data(using: .utf8) {
                        body.append(anEncoding)
                    }
                    if let aKey = postdatadictionary[key], let anEncoding = "\(aKey)".data(using: .utf8) {
                        body.append(anEncoding)
                    }
                    if let anEncoding = "\r\n".data(using: .utf8) {
                        body.append(anEncoding)
                    }
                  }
                }
    
            if let anEncoding = "--\(boundary)--\r\n".data(using: .utf8) {
                body.append(anEncoding)
            }
            // setting the body of the post to the reqeust
            urlRequest.httpBody = body as Data
    
            URLSession.shared.dataTask(with:urlRequest) { (data, response, error) in
                if error != nil {
    
                    print(error!)
                    completion("")
                } else {
                    var dictonary:NSDictionary?
                    do {
                        dictonary = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary
                        if let myDictionary = dictonary
                        {
                            completion(myDictionary)
                        }
                    } catch let error as NSError {
                        completion(error)
                    }
                }
    
                Utils().HideLoader()
    
                }.resume()
    
            }
    
    0 讨论(0)
  • 2020-11-27 13:51

    I implemented Upload image using Multi-part in Swift 4:

    Here is the code. Please have a look

    //MARK: Uplaod User Profile Pic
    func uploadImageToServerFromApp(nameOfApi : NSString, parameters : NSString, uploadedImage : UIImage, withCurrentTask :RequestType, andDelegate :AnyObject)->Void {
        if self.isConnectedToNetwork(){
            currentTask = withCurrentTask
            let myRequestUrl = NSString(format: "%@%@%@",GlobalConstants.KBaseURL,nameOfApi,parameters)
            let url = (myRequestUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed))!
            var request : NSMutableURLRequest = NSMutableURLRequest()
            request = URLRequest(url: URL(string:url as String)!) as! NSMutableURLRequest
            request.httpMethod = "POST"
            let boundary = generateBoundaryString()
            //define the multipart request type
            request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
            let image_data = UIImagePNGRepresentation(uploadedImage)
            if(image_data == nil){
                return
            }
            let body = NSMutableData()
            let fname = "image.png"
            let mimetype = "image/png"
            //define the data post parameter
            body.append("--\(boundary)\r\n".data(using: String.Encoding.utf8)!)
            body.append("Content-Disposition:form-data; name=\"image\"\r\n\r\n".data(using: String.Encoding.utf8)!)
            body.append("hi\r\n".data(using: String.Encoding.utf8)!)
            body.append("--\(boundary)\r\n".data(using: String.Encoding.utf8)!)
            body.append("Content-Disposition:form-data; name=\"image\"; filename=\"\(fname)\"\r\n".data(using: String.Encoding.utf8)!)
            body.append("Content-Type: \(mimetype)\r\n\r\n".data(using: String.Encoding.utf8)!)
            body.append(image_data!)
            body.append("\r\n".data(using: String.Encoding.utf8)!)
            body.append("--\(boundary)--\r\n".data(using: String.Encoding.utf8)!)
            request.httpBody = body as Data
            let session = URLSession.shared
            let task = session.dataTask(with: request as URLRequest) { (data, response, error) in
                guard let data = data, error == nil else {                                                 // check for fundamental networking error
                    // print("error=\(String(describing: error))")
                    self.showAlertMessage(title: "App name", message: "Server not responding, please try later")
                    return
                }
                if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {           // check for http errors
                    // print("statusCode should be 200, but is \(httpStatus.statusCode)")
                    // print("response = \(String(describing: response))")
                    self.delegate?.internetConnectionFailedIssue()
                }else{
                    do {
                        self.responseDictionary = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! NSDictionary
                        // self.Responsedata = data as NSData
                        //self.responseDictionary = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! [String: AnyObject] as NSDictionary;
    
                        self.delegate?.responseReceived()
                    } catch {
                        //print("error serializing JSON: \(error)")
                    }
                }
            }
            task.resume()
        }
        else{
            // print("Internet Connection not Available!")
            self.showAlertMessage(title: "App Name", message: "No Internet Connection..")
        }
    }
    
    func generateBoundaryString() -> String
    {
        return "Boundary-\(NSUUID().uuidString)"
    }
    
    0 讨论(0)
  • 2020-11-27 13:58

    My version that 100% works. Maybe it will help you.

    let url = "http://server/upload"
    let img = UIImage(contentsOfFile: fullPath)
    let data: NSData = UIImageJPEGRepresentation(img, 1)
    
    sendFile(url, 
        fileName:"one.jpg", 
        data:data, 
        completionHandler: completionHandler:{
            (result:Bool, isNoInternetConnection:Bool) -> Void in
    
                // ...     
                NSLog("Complete: \(result)")
        }
    )
    
    
    func sendFile(
        urlPath:String,
        fileName:String,
        data:NSData,
        completionHandler: (NSURLResponse!, NSData!, NSError!) -> Void){
    
            var url: NSURL = NSURL(string: urlPath)!
            var request1: NSMutableURLRequest = NSMutableURLRequest(URL: url)
    
            request1.HTTPMethod = "POST"
    
            let boundary = generateBoundary()
            let fullData = photoDataToFormData(data,boundary:boundary,fileName:fileName)
    
            request1.setValue("multipart/form-data; boundary=" + boundary,
                forHTTPHeaderField: "Content-Type")
    
            // REQUIRED!
            request1.setValue(String(fullData.length), forHTTPHeaderField: "Content-Length")
    
            request1.HTTPBody = fullData
            request1.HTTPShouldHandleCookies = false
    
            let queue:NSOperationQueue = NSOperationQueue()
    
            NSURLConnection.sendAsynchronousRequest(
                request1,
                queue: queue,
                completionHandler:completionHandler)
    }
    
    // this is a very verbose version of that function
    // you can shorten it, but i left it as-is for clarity
    // and as an example
    func photoDataToFormData(data:NSData,boundary:String,fileName:String) -> NSData {
        var fullData = NSMutableData()
    
        // 1 - Boundary should start with --
        let lineOne = "--" + boundary + "\r\n"
        fullData.appendData(lineOne.dataUsingEncoding(
            NSUTF8StringEncoding,
            allowLossyConversion: false)!)
    
        // 2
        let lineTwo = "Content-Disposition: form-data; name=\"image\"; filename=\"" + fileName + "\"\r\n"
        NSLog(lineTwo)
        fullData.appendData(lineTwo.dataUsingEncoding(
            NSUTF8StringEncoding,
            allowLossyConversion: false)!)
    
        // 3
        let lineThree = "Content-Type: image/jpg\r\n\r\n"
        fullData.appendData(lineThree.dataUsingEncoding(
            NSUTF8StringEncoding,
            allowLossyConversion: false)!)
    
        // 4
        fullData.appendData(data)
    
        // 5
        let lineFive = "\r\n"
        fullData.appendData(lineFive.dataUsingEncoding(
            NSUTF8StringEncoding,
            allowLossyConversion: false)!)
    
        // 6 - The end. Notice -- at the start and at the end
        let lineSix = "--" + boundary + "--\r\n"
        fullData.appendData(lineSix.dataUsingEncoding(
            NSUTF8StringEncoding,
            allowLossyConversion: false)!)
    
        return fullData
    }
    
    0 讨论(0)
  • 2020-11-27 13:58

    The first thing I noticed is the application/octet-stream as Conten-Type, this is usually used when the file type is unknown. Some web frameworks/libraries will reject this content-type if an image is required.

    Second, I can't see the post length anywhere, try to add it:

    body.appendString("--\(boundary)--\r\n")
    
    // set the content-length
    request.setValue("\(body.length)", forHTTPHeaderField:"Content-Length")
    
    0 讨论(0)
  • 2020-11-27 13:59

    following those answers here is my implementation with a concrete example for video and audio. notice that the boundary between elements has such form --boundary while the last boundary is written --boudary--.

        let url = URL(string: "https://...")!
        let boundary = UUID().uuidString
        var request = URLRequest(url: url)
        request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
        request.httpMethod = "post"
        var data = Data()
        data.addMultiPart(boundary: boundary, name: "metadata", filename: "metadata.json", contentType: "application/json", data: metaData)
        
        let ext = fileUrl.pathExtension.lowercased()
        let isImage = ["jpg","jpeg","png"].contains(ext)
        let contentType = isImage ? "image/\(ext)" : "video/\(ext)"
        let mediaData = try! Data(contentsOf: fileUrl)
        data.addMultiPart(boundary: boundary, name: "file", filename: fileUrl.lastPathComponent, contentType: contentType, data: mediaData)
        data.addMultiPartEnd(boundary: boundary)
        request.httpBody = data
        let task = session.dataTask(with: request)
        task.resume()
    
    
    private extension Data {
    mutating func addMultiPart(boundary: String, name: String, filename: String, contentType: String, data: Data) {
        print("adding boundary: \(boundary), name: \(name), filename: \(filename), contentType: \(contentType) data length: \(data.count) ")
        self.append("\r\n--\(boundary)\r\n".data(using: .utf8)!)
        self.append("Content-Disposition: form-data; name=\"\(name)\"; filename=\"\(filename)\"\r\n".data(using: .utf8)!)
        self.append("Content-Type: \(contentType)\r\n\r\n".data(using: .utf8)!)
        self.append(data)
    }
    mutating func addMultiPartEnd(boundary: String) {
        self.append("\r\n--\(boundary)--\r\n".data(using: .utf8)!)
    }
    

    }

    0 讨论(0)
提交回复
热议问题