我在下面使用此代码发送多部分参数
let headers = [
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": "Bearer \(myToken)",
"cache-control": "no-cache"
]
let parameters = [
[
"name": "firstname",
"value": "alex"
],
[
"name": "lastname",
"value": "black"
],
[
"name": "birthdate_day",
"value": "1"
],
[
"name": "birthdate_month",
"value": "5"
],
[
"name": "birthdate_year",
"value": "1989"
],
[
"name": "gender",
"value": "m"
],
[
"name": "avatar",
"fileName": "\(imageURL)"
]
]
let boundary = "Boundary-\(NSUUID().uuidString)"
var body = ""
let error: NSError? = nil
for param in parameters {
let paramName = param["name"]!
body += "--\(boundary)\r\n"
body += "Content-Disposition:form-data; name=\"\(paramName)\""
if let filename = param["fileName"] {
if let contentType = param["content-type"] {
do {
let fileContent = try String(contentsOfFile: filename, encoding: String.Encoding.utf8)
if (error != nil) {
print(error as Any)
}
body += "; filename=\"\(filename)\"\r\n"
body += "Content-Type: \(contentType)\r\n\r\n"
body += fileContent
} catch {
print(error)
}
}
} else if let paramValue = param["value"] {
body += "\r\n\r\n\(paramValue)"
}
}
let postData = NSMutableData(data: body.data(using: String.Encoding.utf8)!)
let request = NSMutableURLRequest(url: NSURL(string: "myUrl")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
print(error as Any)
} else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse?.statusCode as Any)
}
})
dataTask.resume()
return dataTask
图像URL和其余数据,但是我将收到Satus代码500,我知道此错误是在服务器端,但是android版本使用的是相同的api URL,并且运行良好,我知道此代码可以修复,并且也许很小的改动就能解决此代码的工作问题
答案 0 :(得分:0)
由于Swift 3使用URL
而不是NSURL,并且
var request = URLRequest
是可变的,请使用它代替NSMutableURLRequest
var data = Data()
是可变的,请使用它代替NSMutableData
Data(contentsOf:options:)
方法安全地添加文件Blob数据content-type
参数缺失,因此使用if let contentType = param["content-type"] { ... }
默认的哑剧类型,application/octet-stream
将无法继续我解决了所有上述问题,并将URLRequest.httpBody
生成的代码移至以下扩展名。
extension URLRequest {
private func formHeader(_ name: String, crlf: String, fileName: String? = nil, mimeType: String? = nil) -> String {
var str = "\(crlf)Content-Disposition: form-data; name=\"\(name)\""
guard fileName != nil || mimeType != nil else { return str + crlf + crlf }
if let name = fileName {
str += "; filename=\"\(name)\""
}
str += crlf
if let type = mimeType {
str += "Content-Type: \(type)\(crlf)"
}
return str + crlf
}
private func getFileUrl(_ file: Any) -> URL? {
if let url = file as? String {
return URL(string: url)
}
return file as? URL
}
private func getFileData(_ url: URL) -> Data? {
do {
return try Data(contentsOf: url, options: .mappedIfSafe)
} catch {
print(error)
return nil
}
}
mutating func setPost(body parameters: [[String: Any]]) {
let boundary = "Boundary+\(arc4random())\(arc4random())"
self.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
var data = Data()
data.append("--\(boundary)".data(using: .utf8)!)
let crlf = "\r\n"
for parameter in parameters {
guard let paramName = parameter["name"] as? String else { continue }
if let value = parameter["value"] {
let header = formHeader(paramName, crlf: crlf)
data.append("\(header)\(value)".data(using: .utf8)!)
} else if let file = parameter["file"], let fileUrl = getFileUrl(file), let fileData = getFileData(fileUrl) {
let fileName = parameter["fileName"] as? String
let contentType = parameter["content-type"] as? String
let header = formHeader(paramName, crlf: crlf, fileName: fileName ?? fileUrl.lastPathComponent, mimeType: contentType ?? "application/octet-stream")
data.append(header.data(using: .utf8)!)
data.append(fileData)
} else {
print("\(paramName): empty or invalid value")
continue
}
data.append("\(crlf)--\(boundary)".data(using: .utf8)!)
}
data.append("--\(crlf)".data(using: .utf8)!)
self.httpBody = data
self.httpMethod = "POST"
}
}
用法
let parameters = [
["name": "firstname", "value": "alex"],
["name": "avatar", "file": URL],
["name": "avatar", "file": "file:///", "fileName": "image.png", "content-type": "image/png"]
]
request.setPost(body: parameters)
在参数中注意
file
键代表URL
对象或文件路径字符串。fileName: image.png
用于后端,代表文件名。最后添加标题并创建URLSession.shared.dataTask
作为原始代码。
Update-2 功能而不是扩展名
func getParameterData(_ name: String, parameter: [String : Any]) -> Data? {
var str = "\r\nContent-Disposition: form-data; name=\"\(name)\""
if let value = parameter["value"] {
return "\(str)\r\n\r\n\(value)".data(using: .utf8)!
}
guard
let file = parameter["file"],
let url = (file is String ? URL(string: file as! String) : file as? URL)
else {
return nil
}
let data: Data
do {
data = try Data(contentsOf: url, options: .mappedIfSafe)
} catch {
print(error)
return nil
}
let fileName = (parameter["fileName"] as? String) ?? url.lastPathComponent
str += "; filename=\"\(fileName)\"\r\n"
let contentType = (parameter["content-type"] as? String) ?? "application/octet-stream"
str += "Content-Type: \(contentType)\r\n"
return (str + "\r\n").data(using: .utf8)! + data
}
func setPostRequestBody(_ request: inout URLRequest, parameters: [[String: Any]]) {
let boundary = "Boundary+\(arc4random())\(arc4random())"
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
var data = Data()
data.append("--\(boundary)".data(using: .utf8)!)
for parameter in parameters {
guard
let name = parameter["name"] as? String,
let value = getParameterData(name, parameter: parameter)
else {
continue
}
data.append(value)
data.append("\r\n--\(boundary)".data(using: .utf8)!)
}
data.append("--\r\n".data(using: .utf8)!)
request.httpBody = data
}
用法2
var request = URLRequest(url: URL(string: "myUrl")!, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0)
setPostRequestBody(&request, parameters: [
["name": "firstname", "value": "alex"],
["name": "avatar", "file": URL object or path String]
])
let dataTask = URLSession.shared.dataTask(with: request) { data, response, error in
guard error != nil else {
print(error!.localizedDescription)
return
}
let statusCocde = (response as? HTTPURLResponse)?.statusCode
print(statusCode ?? 0)
if let data = data {
print(String(data: data, encoding: .utf8) ?? "")
}
}
dataTask.resume()