![](/img/trans.png)
[英]Alamofire4 trouble with JSONResponseSerializer & HTTPURLResponse Swift 3.0
[英]HTTPURLResponse allHeaderFields Swift 3 Capitalisation
轉換為 Swift 3 我注意到從 HTTPURLResponse 讀取標頭字段時發生了一個奇怪的錯誤。
let id = httpResponse.allHeaderFields["eTag"] as? String
不再工作。
我打印了所有標題字典,所有標題鍵似乎都在 Sentence 大小寫中。
根據查爾斯代理的說法,我所有的標題都是小寫的。 根據后端團隊的說法,在他們的代碼中,標題在 Title-Case 中。 根據文檔:標題應該不區分大小寫。
所以我不知道該相信哪個。 有沒有其他人在 Swift 3 中發現他們的標題現在被 iOS 變成了 Sentence 案例? 如果是這樣,我們想要這種行為嗎?
我應該用 Apple 記錄一個錯誤,還是應該在 HTTPURLResponse 上創建一個類別,以允許自己不區分大小寫地查找標頭值。
更新:這是一個已知問題。
allHeaderFields
應該返回一個不區分大小寫的字典,因為這是 HTTP 規范所要求的。 看起來像是 Swift 錯誤,我會在 .
下面是一些簡單地重現問題的示例代碼:
let headerFields = ["ETag" : "12345678"]
let url = URL(string: "http://www.example.com")!
let response = HTTPURLResponse(url: url, statusCode: 200, httpVersion: "HTTP/1.1", headerFields: headerFields)!
response.allHeaderFields["eTaG"] // nil (incorrect)
headerFields["eTaG"] // nil (correct)
(改編自Cédric Luthi 的 Gist 。)
基於@Darko 的回答,我制作了一個Swift 3
擴展,它可以讓您找到任何不區分大小寫的標題:
import Foundation
extension HTTPURLResponse {
func find(header: String) -> String? {
let keyValues = allHeaderFields.map { (String(describing: $0.key).lowercased(), String(describing: $0.value)) }
if let headerValue = keyValues.filter({ $0.0 == header.lowercased() }).first {
return headerValue.1
}
return nil
}
}
更有效的解決方法:
(response.allHeaderFields as NSDictionary)["etag"]
作為 Swift 3 的修補程序,您可以執行以下操作:
// Converting to an array of tuples of type (String, String)
// The key is lowercased()
let keyValues = response.allHeaderFields.map { (String(describing: $0.key).lowercased(), String(describing: $0.value)) }
// Now filter the array, searching for your header-key, also lowercased
if let myHeaderValue = keyValues.filter({ $0.0 == "X-MyHeaderKey".lowercased() }).first {
print(myHeaderValue.1)
}
更新:這個問題似乎仍然沒有在 Swift 4 中得到解決。
我點擊了這個並使用Dictionary
上的擴展來解決它來創建自定義下標。
extension Dictionary {
subscript(key: String) -> Value? {
get {
let anyKey = key as! Key
if let value = self[anyKey] {
return value // 1213ns
}
if let value = self[key.lowercased() as! Key] {
return value // 2511ns
}
if let value = self[key.capitalized as! Key] {
return value // 8928ns
}
for (storedKey, storedValue) in self {
if let stringKey = storedKey as? String {
if stringKey.caseInsensitiveCompare(key) == .orderedSame {
return storedValue // 22317ns
}
}
}
return nil
}
set {
self[key] = newValue
}
}
}
評論中的時間來自對不同場景的基准測試(優化構建, -Os
,平均超過 1,000,000 次迭代)。 標准字典的等效訪問時間為 1257ns。 必須進行兩次檢查才能有效地增加一倍,2412ns。
在我的特定情況下,我看到從服務器返回的標頭是駝峰式或小寫,具體取決於我連接的網絡(其他需要調查的情況)。 這樣做的好處是,如果它得到修復,我可以刪除擴展名而無需更改其他任何內容。 此外,使用該代碼的任何其他人都不需要記住任何解決方法 - 他們可以免費獲得這個。
我檢查並沒有看到ETag
被HTTPURLResponse
修改 - 如果我傳遞了它ETag
或Etag
我在allHeaderFields
得到了那些。 如果性能是一個問題,並且您遇到此問題,您可以創建第二個下標,該下標采用包含數組的Hashable
結構。 然后將它傳遞給字典,並帶有您要處理的標簽。
struct DictionaryKey: Hashable {
let keys: [String]
var hashValue: Int { return 0 } // Don't care what is returned, not going to use it
}
func ==(lhs: DictionaryKey, rhs: DictionaryKey) -> Bool {
return lhs.keys == rhs.keys // Just filling expectations
}
extension Dictionary {
subscript(key: DictionaryKey) -> Value? {
get {
for string in key.keys {
if let value = self[string as! Key] {
return value
}
}
return nil
}
}
}
print("\(allHeaderFields[DictionaryKey(keys: ["ETag", "Etag"])])"
正如您所期望的,這幾乎等同於進行單獨的字典查找。
對於 swift 3.0,有一個比 Darko 短一點的版本。
由於 iOS8 和 iOS10 中的標題名稱大小寫可能不同,因此最好的方法是使用不區分大小寫的比較。
response.allHeaderFields.keys.contains(where: {$0.description.caseInsensitiveCompare("CaSe-InSeNsItIvE-HeAdEr") == .orderedSame})
所以現在支持所有類型:
這是我的。 我沒有弄亂字典的工作方式,而是在NSHTTPURLResponse
上NSHTTPURLResponse
了一個 obj-c 類別。 Obj-C allHeaderFields
字典仍然不區分大小寫。
@import Foundation;
@implementation NSHTTPURLResponse (CaseInsensitive)
- (nullable NSString *)allHeaderFieldsValueForCaseInsensitiveKey:(nonnull NSString *)key {
NSString *value = self.allHeaderFields[key];
if ([value isKindOfClass:[NSString class]]) {
return value;
} else {
return nil;
}
}
@end
對於簡單的案例使用
if let ix = headers.index(where: {$0.key.caseInsensitiveCompare("eTag") == .orderedSame}){
let tag = headers[ix].value
}
在swift 4.1
它對我有用。
if let headers = httpResponse.allHeaderFields as? [String: String], let value = headers["key"] {
print("value: \(value)")
}
如果不能像下面那樣工作,您也可以使用.lowercased()
和.capitalized
值(根據您的情況)
httpResponse.allHeaderFields["eTag".capitalized] as? String
httpResponse.allHeaderFields["eTag". lowercased()] as? String
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.