The Tips of allHeaderFields in NSURLResponse

这两天提交 APP Store 被拒审了,排查之后发现是 NSHTTPURLResponse 中的 allHeaderFields 的一个坑。

根据 RFC2616 的描述,header 中的字段是大小写不敏感的,也就是,你写 Foofoo 或者是 fOo 是一样的,但是苹果在的实现是,当你 set 的时候,是按照你写的 key-value 来,当你再次设置的时候,是按照大小写不敏感的方式来查找 set,之后在设置进去。

In Objective-C, the returned dictionary of headers is case-preserving during the set operation (unless the key already exists with a different case), and case-insensitive when looking up keys.
For example, if you set the header X-foo, and then later set the header X-Foo, the dictionary’s key is be X-foo, but the value comes from the X-Foo header.

而苹果在 iOS 13 新增了一个方法,这个方法将会用大小写不敏感的方式来查找 key,然后返回对应的 value。

1
2
3
4
5
6
7
8
9
10
11
12
/*!
@method valueForHTTPHeaderField:
@abstract Returns the value which corresponds to the given header
field. Note that, in keeping with the HTTP RFC, HTTP header field
names are case-insensitive.
@param field the header field name to use for the lookup
(case-insensitive).
@result the value associated with the given header field, or nil if
there is no value associated with the given header field.
*/
- (nullable NSString *)valueForHTTPHeaderField:(NSString *)field API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0));

实际测试如下

1
2
3
4
5
NSHTTPURLResponse *res = [[NSHTTPURLResponse alloc] initWithURL:[NSURL URLWithString:@"https://www.baidu.com"] statusCode:200 HTTPVersion:@"1.1" headerFields:@{@"foo": @"2", @"Foo": @"3", @"FOo": @"4", @"bar": @"1", @"Bar": @"2"}];

NSLog(@"%@", res.allHeaderFields);

NSLog(@"%@", [res valueForHTTPHeaderField:@"fOO"]);

其输出结果是

1
2
3
4
5
6
{
Bar = 2;
FOo = 4;
}

4

这么看的话,似乎和文档描述的并不太一样,最后打印出来的 key 是 FOo 也就是最后添加进去的,而 Bar 也是最后添加进去的,key 会覆盖,value 也会覆盖。。。。