HTTPURLResponse allHeaderFields斯威夫特资本3

问题描述 投票:9回答:9

转换为斯威夫特3,我注意到一个奇怪的错误发生,从HTTPURLResponse读取头字段。

let id = httpResponse.allHeaderFields["eTag"] as? String

不再奏效。

我打印出所有头,字典和我的所有头键似乎是句首字母大写。

据查尔斯代理所有我的头是小写。根据后端团队,在他们的代码中的头是在标题案例。根据文档:标题应该是不区分大小写。

所以,我不知道该相信哪个。是任何人都在斯威夫特3发现他们的头现在正在变成句首字母大写,内部监督办公室?如果是的话是这样的行为,我们想要的吗?

我应该记录与苹果的错误或我应该就HTTPURLResponse一个类别,让自己不区分大小写区分找到一个标头值。

ios http swift3 case-insensitive nshttpurlresponse
9个回答
10
投票

更新:这是一个known issue


allHeaderFields应该返回一个不区分大小写的字典,因为这是HTTP规范要求。看起来像雨燕的错误,我会提起雷达或错误报告。

下面是简单地再现问题的一些示例代码:

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)

(从this Gist from Cédric Luthi改编)。


5
投票

根据@达科的答案我已经作出了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
    }

}

1
投票

我打了这一点,并使用上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,平均超过百万次迭代)。标准字典的等效访问,在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"])])"

这是,如你所期望的,几乎等同于使个人字典查找。


1
投票

作为一个热修复的斯威夫特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)
}

更新:这个问题似乎仍然没有被固定在斯威夫特4。


1
投票

更有效的解决方法:

(response.allHeaderFields as NSDictionary)["etag"]

0
投票

有一点点位短版本比达科对SWIFT 3.0。

由于这样的事实,即在头名的情况下可以在iOS 8的不同,iOS10所以最好的方法就是使用比较不敏感的情况下。

response.allHeaderFields.keys.contains(where: {$0.description.caseInsensitiveCompare("CaSe-InSeNsItIvE-HeAdEr") == .orderedSame})

因此,所有类型现在支持:

  • 不区分大小写的报头
  • 不区分大小写的,头
  • 不区分大小写,HEADER

0
投票

这里是我的。相反,与字典的工作方式乱搞的,我做了一个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

0
投票

对于简单的情况下使用

if let ix = headers.index(where: {$0.key.caseInsensitiveCompare("eTag") == .orderedSame}){
    let tag = headers[ix].value
}

0
投票

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
© www.soinside.com 2019 - 2024. All rights reserved.