我的多部件表单数据编码器有什么问题?斯威夫特 4.



Hello( 这是我的 MultiPartFormDataEncoder:

let boundary =  "Boundary-(UUID().uuidString)"
var body = ""
if let parameters = parameters {
for (key, value) in parameters {
body += "--(boundary)rn"
body += "Content-Disposition:form-data; name="(String(describing: key))"rnrn"
body += "(String(describing: value))rn"
}
}
if let files = files {
for file in files {
body += "--(boundary)rn"
body += "Content-Disposition: form-data; name="(file.key)"; filename="(file.name)"rn"
body += "Content-Type: (file.type)rnrn"
body += "(file.data)rn"
}
}
body += "--".appending(boundary.appending("--"))
urlRequest.httpBody = body.data(using: .utf8)
if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {
urlRequest.setValue("multipart/form-data; charset=utf8; boundary=(boundary)", forHTTPHeaderField: "Content-Type")
}
urlRequest.timeoutInterval = 60
urlRequest.httpShouldHandleCookies = false

向服务器发送请求后,我收到"错误请求"。当我尝试在邮递员请求中这样做时,就是成功。 所有参数和文件都具有正确的名称、类型和键。我肯定检查了一个。 所以问题不在后端,因为它得到了我的请求并看到了正确的正文,但它在得到后就坏了。

我认为标题有问题。

那么,你怎么看?

编辑: 正确响应解析后,我看到下一条消息:

{"图片":["上传有效图片。您上传的文件不是图像或损坏的图像。

所以,我找到了问题和解决方案。

错误出现在这一行中:

body += "(file.data)rn"

正如@Larme所说,我们不能将数据和字符串放在一行中。

更好的解决方案是分别添加数据和字符串,例如:

// old body += "(file.data)rn"
// new:
var body: Data = Data()
body.append(file.data)
body.append("rn".data(using: .utf8)!)

在我的例子中,MultiPartFormDataParameterEncoder将看起来像:

func encode(urlRequest: inout URLRequest, with parameters: Parameters?, files: Files?) throws {
do {
let boundary =  "Boundary-(UUID().uuidString)"
var body: Data = Data()
if let parameters = parameters {
for (key, value) in parameters {
try body.appendString("--(boundary)rn")
try body.appendString("Content-Disposition:form-data; name="(String(describing: key))"rnrn")
try body.appendString("(String(describing: value))rn")
}
}
if let files = files {
for file in files {
try body.appendString("--(boundary)rn")
try body.appendString("Content-Disposition: form-data; name="(file.key)"; filename="(file.name)"rn")
try body.appendString("Content-Type: "(file.type)"rnrn")
body.append(file.data)
try body.appendString("rn")
}
}
try body.appendString("--".appending(boundary.appending("--")))
urlRequest.httpBody = body
if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {
urlRequest.addValue("multipart/form-data; boundary=(boundary)", forHTTPHeaderField: "Content-Type")
}
} catch {
throw NetworkError.encodingMultiPartFormDataFailed
}
}
public enum NetworkError: String, Error {
case encodingMultiPartFormDataFailed = "Parameter encoding in MultiPartFormData failed ..."
}

还必须添加文件和参数模型:

public typealias Parameters = [String:Any]
public typealias Files = [FileModel]
public struct FileModel {
let name: String
let key: String
let data: Data
let type: String
init(name: String, type: FileType, data: Data) {
self.name = name
self.key = type.key // will be image or audio
self.data = data
self.type = type.rawValue // will be "audio/mp3" or "image/jpeg"
}
}
extension FileModel {
enum FileType: String {
case image = "image/jpeg"
case audio = "audio/mp3"
var key: String {
return String(describing: self)
}
}
}
// USAGE EXAMPLE
FileModel(name: name, type: .image, data: imageJpegData)

也不要忘记数据扩展名以提高安全性:

extension Data {
private enum DataError: String, Error {
case encodingStringToDataFailed = "Encoding String to Data failed ..."
}
mutating func appendString(_ string: String) throws {
guard let data: Data = string.data(using: String.Encoding.utf8, allowLossyConversion: false) else {
throw DataError.encodingStringToDataFailed
}
append(data)
}
}

谢谢 ^_^

最新更新