使用Swift中的多部分表单数据iOS上传图像

我有一个与多部分forms上传图像的问题

这里是我从这个答案使用的代码

var request = NSMutableURLRequest(URL: url!) request.HTTPMethod = "POST" var boundary = generateBoundaryString() request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type") var body = NSMutableData() if self.img.image != nil { var imageData = UIImagePNGRepresentation(self.img.image) if imageData != nil { body.appendString("--\(boundary)\r\n") body.appendString("Content-Disposition: form-data; name=\"image\"; filename=\"image.png\"\r\n") body.appendString("Content-Type: image/png\r\n\r\n") body.appendData(imageData!) body.appendString("\r\n") } } body.appendString("--\(boundary)--\r\n") request.setValue("\(body.length)", forHTTPHeaderField:"Content-Length") request.HTTPBody = body 

然后我使用NSURLSession来应用请求

服务器说,我没有select图像上传,我只想现在上传图像

我必须使用图像path来上传任何图像或它的数据是足够的吗?

我想念任何事情吗,任何帮助理解这一点?

我的版本,100%的作品。 也许它会帮助你。

 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 } 
 public func UPLOADIMG(url: String,parameters: Dictionary<String,AnyObject>?,filename:String,image:UIImage, success:((NSDictionary) -> Void)!, failed:((NSDictionary) -> Void)!, errord:((NSError) -> Void)!) { var TWITTERFON_FORM_BOUNDARY:String = "AaB03x" let url = NSURL(string: url)! var request:NSMutableURLRequest = NSMutableURLRequest(URL: url, cachePolicy: NSURLRequestCachePolicy.ReloadIgnoringLocalCacheData, timeoutInterval: 10) var MPboundary:String = "--\(TWITTERFON_FORM_BOUNDARY)" var endMPboundary:String = "\(MPboundary)--" //convert UIImage to NSData var data:NSData = UIImagePNGRepresentation(image) var body:NSMutableString = NSMutableString(); // with other params if parameters != nil { for (key, value) in parameters! { body.appendFormat("\(MPboundary)\r\n") body.appendFormat("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n") body.appendFormat("\(value)\r\n") } } // set upload image, name is the key of image body.appendFormat("%@\r\n",MPboundary) body.appendFormat("Content-Disposition: form-data; name=\"\(filename)\"; filename=\"pen111.png\"\r\n") body.appendFormat("Content-Type: image/png\r\n\r\n") var end:String = "\r\n\(endMPboundary)" var myRequestData:NSMutableData = NSMutableData(); myRequestData.appendData(body.dataUsingEncoding(NSUTF8StringEncoding)!) myRequestData.appendData(data) myRequestData.appendData(end.dataUsingEncoding(NSUTF8StringEncoding)!) var content:String = "multipart/form-data; boundary=\(TWITTERFON_FORM_BOUNDARY)" request.setValue(content, forHTTPHeaderField: "Content-Type") request.setValue("\(myRequestData.length)", forHTTPHeaderField: "Content-Length") request.HTTPBody = myRequestData request.HTTPMethod = "POST" // var conn:NSURLConnection = NSURLConnection(request: request, delegate: self)! let task = NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: { data, response, error in if error != nil { println(error) errord(error) return } var parseError: NSError? let responseObject: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: &parseError) if let responseDictionary = responseObject as? NSDictionary { success(responseDictionary) } else { } }) task.resume() } 

我注意到的第一件事情是application/octet-stream作为Conten-Type ,通常在文件types未知时使用。 如果需要图像,某些Web框架/库将拒绝此内容types。

其次,我看不到任何地方的post长度,尝试添加它:

 body.appendString("--\(boundary)--\r\n") // set the content-length request.setValue("\(body.length)", forHTTPHeaderField:"Content-Length") 

我使用Swift 4中的多部分实现了上传图像:

这是代码。 请看一看

 //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)" }