Swift 5,Xcode版本10.2.1(10E1001)
大家好,我对此表示感谢。
我正在创建一个呼叫,以将附件(PNG)发布到我的POST呼叫中。我正在拨打ServiceNow。如果我在正文中使用与PostMan相同的键,则Postman中的调用会正常工作。但是,下面的附件似乎很难。此示例中的图片是PNG资产。
为进行比较,如果我在Postman中省略附件,则会得到完全相同的错误消息。我相信图片格式不正确...
预先感谢...
我从ServiceNow中收到以下错误:
{
error = {
detail = "<null>";
message = "Failed to create the attachment. File part might be missing in the request.";
};
status = failure;
}
这是我的代码:
func createDataBody() -> Data {
let newLine = "\r\n"
let twoNewLines = newLine + newLine
let boundary = "----------------------------\(UUID().uuidString)" + newLine
var body = Data()
let stringEncoding = String.Encoding.utf16
body.append(boundary.data(using: stringEncoding)!)
let table_name = "Content-Disposition: form-data; name=\"table_name\"" + twoNewLines
body.append(table_name.data(using: stringEncoding)!)
//incident
body.append("incident".data(using: stringEncoding)!)
//new line
body.append(newLine.data(using: stringEncoding)!)
//boundary
body.append(boundary.data(using: stringEncoding)!)
let table_sys_id = "Content-Disposition: form-data; name=\"table_sys_id\"" + twoNewLines
body.append(table_sys_id.data(using: stringEncoding)!)
//ba931ddadbf93b00f7bbdd0b5e96193c
body.append("ba931ddadbf93b00f7bbdd0b5e96193c".data(using: stringEncoding)!)
//new line
body.append(newLine.data(using: stringEncoding)!)
//boundary
body.append(boundary.data(using: stringEncoding)!)
let file = "Content-Disposition: form-data; name=\"file\"; filename=\"Artboard@1x.png\"" + newLine
body.append(file.data(using: stringEncoding)!)
let type = "Content-Type: image/png" + twoNewLines
body.append(type.data(using: stringEncoding)!)
//new line
body.append(newLine.data(using: stringEncoding)!)
let img = #imageLiteral(resourceName: "Artboard@1x")
if let fileContent = img.pngData() {
body.append(fileContent)
}
//new line
body.append(newLine.data(using: stringEncoding)!)
body.append("--\(UUID().uuidString)--".data(using: stringEncoding)!)
print(String(data: body, encoding: .utf16)!)
return body
}
这是身体的样子,省略了图像数据:
----------------------------F2152BF1-CE54-4E86-B8D0-931FA36F7C36
Content-Disposition: form-data; name="table_name"
incident
----------------------------F2152BF1-CE54-4E86-B8D0-931FA36F7C36
Content-Disposition: form-data; name="table_sys_id"
ba931ddadbf93b00f7bbdd0b5e96193c
----------------------------F2152BF1-CE54-4E86-B8D0-931FA36F7C36
Content-Disposition: form-data; name="file"; filename="Artboard@1x.png"
Content-Type: image/png
.....
----------------------------F2152BF1-CE54-4E86-B8D0-931FA36F7C36
这是标题调用
func addAttachmentToIncident(){
let passwordString = "\(userNameTextField.text!):\(passwordTextField.text!)"
let passwordData = passwordString.data(using: String.Encoding.utf8)
let base64EncodedCredential = passwordData?.base64EncodedString(options: Data.Base64EncodingOptions.lineLength76Characters)
let boundary = generateBoundaryString()
let headers = [
"authorization": "Basic " + base64EncodedCredential!,
"cache-control": "no-cache",
"Accept": "application/json",
"content-type": "multipart/form-data; boundary=--\(boundary)"
]
guard let url = URL(string: "https://xxx.service-now.com/api/now/attachment/upload") else {
return
}
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
let dataBody = createDataBody(boundary: boundary)
request.httpBody = dataBody
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) in
if let response = response {
print(response)
}
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: [])
print(json)
} catch {
print(error)
}
}
}.resume()
} // addAttachmentToIncident
答案 0 :(得分:1)
一些观察结果:
最终边界不正确。假设您已经创建了一个以--
开头的边界,则应该附加\(boundary)--
作为最终边界。现在,代码正在创建一个新的UUID(并省略了您在原始边界中添加的所有多余破折号),因此它将与其余边界不匹配。您也需要在该最终边界之后加上一个newLine
序列。
缺少最终边界可能会阻止它识别出身体的这一部分,因此“文件部分可能丢失”消息。
boundary
不应是局部变量。准备多部分请求时,必须在标头中指定边界(此处必须是同一边界,而不是另一个UUID()
实例)。
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
通常,我会让调用者创建边界,在创建请求标头时使用边界,然后将边界作为参数传递给此方法。参见Upload image with parameters in Swift。
标题和正文中没有相同的边界值将阻止它识别正文的任何这些部分。
您已定义本地边界以包括newLine
。显然,它根本不应该是local var,但结尾不能包含换行符,否则尝试附加/(boundary)--
的最后一个边界将失败。
很明显,如果您将此内容排除在边界之外,则请确保在构建主体时在需要的地方插入适当的换行符。最重要的是,确保您的身体看起来像下面的样子(带有最后的--
):
----------------------------F2152BF1-CE54-4E86-B8D0-931FA36F7C36
Content-Disposition: form-data; name="table_name"
incident
----------------------------F2152BF1-CE54-4E86-B8D0-931FA36F7C36
Content-Disposition: form-data; name="table_sys_id"
ba931ddadbf93b00f7bbdd0b5e96193c
----------------------------F2152BF1-CE54-4E86-B8D0-931FA36F7C36
Content-Disposition: form-data; name="file"; filename="Artboard@1x.png"
Content-Type: image/png
.....
----------------------------F2152BF1-CE54-4E86-B8D0-931FA36F7C36--
在curl
的{{1}} example中,他们使用的字段名称为/now/attachment/upload
,但是您正在使用uploadFile
。您可能需要仔细检查您的字段名称,并匹配file
和邮递员示例。
curl
如果解决了上述问题后仍然无法解决问题,建议您使用Charles或Wireshark并将成功的请求与您以编程方式生成的请求进行比较。
不用说,您可能想考虑使用Alamofire,这使您摆脱了创建格式正确的多部分请求的麻烦。