2016-10-20 6 views
8

Swift 3への変換HTTPURLResponseのヘッダーフィールドを読み取る際に奇妙なバグが発生していることがわかりました。HTTPURLResponse allHeaderFields Swift 3大文字化

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

もはや機能しません。

すべてのヘッダー辞書を印刷しました。すべてのヘッダーキーがSentenceの場合のようです。

チャールズプロキシによれば、すべてのヘッダーは小文字です。バックエンドチームによれば、そのコードではヘッダーがTitle-Caseにあります。ドキュメントによれば、ヘッダーは大文字と小文字を区別しません。

だから私は信じるべきか分からない。スウィフト3でヘッダーがiOSによってSentenceのケースに変わっていることを知っている人はいませんか?もしそうなら、私たちが望むこの行動は?

Appleにバグを記録するか、HTTPURLResponseでカテゴリを作成して、ヘッダ値を無意識に見つけることができますか。

答えて

8

更新:これは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から適応。)

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) 
} 

更新:この問題は、まだSwift 4では修正されていないようです。

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、1,000,000を超える反復平均)。標準辞書の同等のアクセスは、1257nsで出てきました。 2つの小切手を作ることが効果的に2倍になりました。

私の具体的なケースでは、私が接続していたネットワーク(調査する何か他のもの)によって、ラクダのケースか小文字だったサーバーからヘッダが戻ってくるのを見ていました。これは、修正が必要な場合は、拡張機能を削除するだけで、変更する必要はないという利点があります。また、コードを使用している誰もが何らかの回避策を思い出す必要はありません。無料でこのコードを取得します。

私がチェックしETagHTTPURLResponseによって変更されて表示されませんでした - 私はそれをETag、またはEtagを通過した場合、私はallHeaderFieldsにそれらの背中を得ました。パフォーマンスが懸念され、この問題が発生した場合、配列を含むHashable構造体を受け取る2番目の添字を作成できます。次に、それを処理したいタグとともにDictionaryに渡します。

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"])])" 

これは、予想通り、個々の辞書のルックアップとほぼ同じです。

0

Swift 3.0のDarkoよりも少し短いバージョンがあります。

実際、iOS8とiOS10ではヘッダー名のケースが異なる可能性があるため、大文字と小文字を区別しない比較を使用することをお勧めします。

  • 大文字と小文字を区別しないヘッダ
  • ケース・センシティブ・ヘッダー
  • 大文字と小文字を区別しない-HEADER
2

@に基づいて:だから、すべてのタイプがサポートされるようになりました

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

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 
    } 

} 
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 
} 
関連する問題