我正在尝试上传图片和文本文件(将其上传为数据)。
到目前为止,我可以正确地单独上传图像,也可以成功上传文本文件数据,并以.txt格式成功上传。
现在,我需要同时上传图片和.txt文件…
我不确定如何在我的IOS应用中为此设置参数…。
到目前为止,这就是我上传.txt文件的方式(基本上与我上传图片的方式相同,但是我更改了“文件名”和“ mimetype”)
func createBodyWithParameters(parameters: [String : Any]?, filePathKey: String?,filePathKey1: String?, imageDataKey: NSData,imageDataKey1: NSData, 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") } } let filename = "post-\(uuid).txt" let mimetype = "image/txt" 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.append(imageDataKey as Data) body.appendString("\r\n") body.appendString("--\(boundary)--\r\n") return body }
现在,我不确定如何使用该参数保存图像和.txt文件。
但是,这是我快速上传代码的其余部分:
let param = [ "id" : id, "uuid" : uuid, "Text" : Text, "Title" : Title ] as [String : Any] let boundary = "Boundary-\(NSUUID().uuidString)" request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type") let data: Data = NSKeyedArchiver.archivedData(withRootObject: blogattributedText) var imageData = NSData() let image = CoverImage let width = CGSize(width: self.view.frame.width, height: image.size.height * (self.view.frame.width / image.size.width)) imageData = UIImageJPEGRepresentation(imageWithImage(image, scaledToSize: width), 0.5)! as NSData // ... body request.httpBody = createBodyWithParameters(parameters: param, filePathKey: "file",filePathKey1: "file1", imageDataKey: data as NSData,imageDataKey1: imageData as NSData, boundary: boundary) as Data
如果有人需要查看我的代码或不明白我的问题,请告诉我!
在此先感谢任何可以提供帮助的人!
如果您不想迷失在创建复杂请求的过程中,那么像Alamofire这样的第三方库将很聪明。它与AFNetworking的作者相同,但是它是本机Swift库。
因此,Alamofire实现可能如下所示:
func performRequest(urlString: String, id: String, uuid: String, text: String, title: String, blogAttributedText: NSAttributedString, image: UIImage) { let parameters = [ "id" : id, "uuid" : uuid, "Text" : text, "Title" : title ] let imageData = UIImageJPEGRepresentation(image, 0.5)! let blogData = NSKeyedArchiver.archivedData(withRootObject: blogAttributedText) Alamofire.upload( multipartFormData: { multipartFormData in for (key, value) in parameters { if let data = value.data(using: .utf8) { multipartFormData.append(data, withName: key) } } multipartFormData.append(imageData, withName: "image", fileName: "image.jpg", mimeType: "image/jpeg") multipartFormData.append(blogData, withName: "blog", fileName: "blog.archive", mimeType: "application/octet-stream") }, to: urlString, encodingCompletion: { encodingResult in switch encodingResult { case .success(let upload, _, _): upload .validate() .responseJSON { response in switch response.result { case .success(let value): print("responseObject: \(value)") case .failure(let responseError): print("responseError: \(responseError)") } } case .failure(let encodingError): print("encodingError: \(encodingError)") } }) }
如果您要自己建立此请求,我建议一些事情。首先,由于您要发送不同类型的文件,因此可能需要一些不错的类型来封装它:
struct FilePayload { let fieldname: String let filename: String let mimetype: String let payload: Data }
我也不知道该如何制作image/txt哑剧类型。我可能会使用application/octet-stream存档。
image/txt
application/octet-stream
无论如何,请求的构建可能如下:
/// Create request. /// /// - Parameters: /// - url: The URL to where the post will be sent. /// - id: The identifier of the entry /// - uuid: The UUID of the entry /// - text: The text. /// - title: The title. /// - blogAttributedText: The attributed text of the blog entry. /// - image: The `UIImage` of the image to be included. /// /// - Returns: The `URLRequest` that was created func createRequest(url: URL, id: String, uuid: String, text: String, title: String, blogAttributedText: NSAttributedString, image: UIImage) -> URLRequest { let parameters = [ "id" : id, "uuid" : uuid, "Text" : text, // I find it curious to see uppercase field names (I'd use lowercase for consistency's sake, but use whatever your PHP is looking for) "Title" : title ] let boundary = "Boundary-\(NSUUID().uuidString)" var request = URLRequest(url: url) request.httpMethod = "POST" request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type") request.setValue("application/json", forHTTPHeaderField: "Accept") // adjust if your response is not JSON // use whatever field name your PHP is looking for the image; I used `image` let imageData = UIImageJPEGRepresentation(image, 0.5)! let imagePayload = FilePayload(fieldname: "image", filename: "image.jpg", mimetype: "image/jpeg", payload: imageData) // again, use whatever field name your PHP is looking for the image; I used `blog` let blogData = NSKeyedArchiver.archivedData(withRootObject: blogAttributedText) let blogPayload = FilePayload(fieldname: "blog", filename: "blog.archive", mimetype: "application/octet-stream", payload: blogData) request.httpBody = createBody(with: parameters, files: [imagePayload, blogPayload], boundary: boundary) return request } /// Create body of the multipart/form-data request. /// /// - Parameters: /// - parameters: The optional dictionary containing keys and values to be passed to web service. /// - files: The list of files to be included in the request. /// - boundary: The `multipart/form-data` boundary /// /// - Returns: The `Data` of the body of the request. private func createBody(with parameters: [String: String]?, files: [FilePayload], boundary: String) -> Data { var body = Data() if parameters != nil { for (key, value) in parameters! { body.append("--\(boundary)\r\n") body.append("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n") body.append("\(value)\r\n") } } for file in files { body.append("--\(boundary)\r\n") body.append("Content-Disposition: form-data; name=\"\(file.fieldname)\"; filename=\"\(file.filename)\"\r\n") body.append("Content-Type: \(file.mimetype)\r\n\r\n") body.append(file.payload) body.append("\r\n") } body.append("--\(boundary)--\r\n") return body } /// Create boundary string for multipart/form-data request /// /// - returns: The boundary string that consists of "Boundary-" followed by a UUID string. private func generateBoundaryString() -> String { return "Boundary-\(NSUUID().uuidString)" }
哪里
extension Data { /// Append string to Data /// /// Rather than littering my code with calls to `dataUsingEncoding` to convert strings to `Data`, and then add that data to the `Data`, this wraps it in a nice convenient little `Data` extension. This converts using UTF-8. /// /// - parameter string: The string to be added to the mutable `Data`. mutating func append(_ string: String) { if let data = string.data(using: .utf8) { append(data) } } }
显然,这是Swift 3代码,因此我删除了NSMutableData参考。
NSMutableData