【发布时间】:2016-06-03 09:03:16
【问题描述】:
场景:
- iPhone iOS 8+ 应用程序
- 登录用户将上传个人资料图片
该应用已使用 Alamofire 向后端 API 发出签名请求。非常简单:应用程序发送三个特定的 HTTP 标头(Authorization、X-Api-Key 和 timestamp)以供签名请求。调用Alamofire.request 很容易将headers 作为参数发送,所以它工作得很好。
现在用户需要能够上传他们的个人资料图片。由于用户已经登录到应用程序,后端 API 将通过 签名请求 知道哪个用户正在发送图片 - 这是过去几个小时我一直在努力解决的棘手部分。 Alamofire.upload 接受与.request 完全不同的参数,所以我不知道在上传文件时如何发送标头。
尝试了旧的Alamofire.Manager.session.configuration.HTTPAdditionalHeaders,但它是no longer supported。找到大量文件上传的代码示例,没有考虑发送自定义标头。
使用Alamofire.upload 方法时如何发送自定义标头?
typealias requestDataType = [String:AnyObject]
private func signRequest(data: requestDataType) -> [String:String] {
var headers = [String:String]()
var authString = ""
var signatureHeaders = ""
// Iterates over SORTED data dictionary to build headers
for (k,v) in (data.sort{$0.0 < $1.0}) {
if !authString.isEmpty {
authString += "\n"
signatureHeaders += " "
}
authString += "\(k): \(v)"
signatureHeaders += "\(k)"
headers[k] = "\(v)"
}
let userApiKey = _loggedInUser!["api_key"].string!
let signature = authString.sha256(_loggedInUser!["api_secret"].string!)
headers["X-Api-Key"] = userApiKey
headers["Authorization"] = "Signature headers=\"\(signatureHeaders)\",keyId=\"\(userApiKey)\",algorithm=\"hmac-sha256\",signature=\"\(signature)\""
return headers
}
func uploadProfilePicture(photo: UIImage, callback: apiCallback){
guard let userId = _loggedInUser?["pk"].int else {
callback(Response(success: false, responseMessage: "User not logged in"))
return
}
let requestData: requestDataType = ["timestamp": "\(Int(NSDate().timeIntervalSince1970))"]
let aManager = Manager.sharedInstance
print(self.signRequest(requestData)) // Prints correct headers (Authorization, X-Api-Key, timestamp)
aManager.session.configuration.HTTPAdditionalHeaders = self.signRequest(requestData)
print(aManager.session.configuration.HTTPAdditionalHeaders) // Prints default headers, completely ignoring my custom headers
aManager.upload(.POST, "\(_apiBaseUrl)profiles/\(userId)/photo/", multipartFormData: { multipartFormData in
if let imageData = UIImageJPEGRepresentation(photo, 0.8) {
multipartFormData.appendBodyPart(data: imageData, name: "upload", fileName: "userphoto.jpg", mimeType: "image/jpeg")
}
for (key, value) in requestData {
multipartFormData.appendBodyPart(data: value.dataUsingEncoding(NSUTF8StringEncoding)!, name: key)
}
}, encodingCompletion: {
encodingResult in
debugPrint(encodingResult)
})
}
请求通过。在后端日志中,我可以看到返回的请求 HTTP 403 - 未授权,因为无法签署请求。打印请求标头,服务器未收到自定义身份验证标头。
【问题讨论】:
-
至少添加
signRequest方法的原型 -
@DavidBerry 已更新。
标签: ios swift httprequest alamofire multipartform-data