Укажите HTTPVersion для NSHTTPURLResponse

В моем приложении используется пользовательский подкласс NSURLProtocol. Мне нужно заменить NSHTTPURLResponse своей копией, изменив некоторые поля заголовков. Итак, я создаю новый экземпляр NSHTTPURLResponse, например:

@implementation NSHTTPURLResponse (CocoaFix)

- (instancetype)HTTPResponseByRemovingValueForHeaderFields:(NSArray *)fields {
    NSMutableDictionary *mutableHeaderFields = [self.allHeaderFields mutableCopy];
    [mutableHeaderFields removeObjectsForKeys:fields];
    return [[[self class] alloc] initWithURL:self.URL
                                  statusCode:self.statusCode
                                 HTTPVersion:@"HTTP/1.1" // What should I pass here?
                                headerFields:mutableHeaderFields];
}

@end

Проблема возникает с параметром HTTPVersion. Я не нашел способа получить это значение из исходного ответа.

В документации говорится:

Обычно это представляется как «HTTP/1.1».

Но предоставление жестко заданного значения не похоже на решение, которое будет работать правильно все время.

Пожалуйста, помогите мне с этим.


person Borys Verebskyi    schedule 23.03.2016    source источник


Ответы (3)


В соответствии с этим ответом: https://stackoverflow.com/questions/9312669/nsurlrequest-http-protocol-version, вам, вероятно, нужно хотя бы подключиться к API-интерфейсам CFNetwork. сделать это.

person fullofsquirrels    schedule 23.03.2016
comment
Спасибо за ваши старания. Насколько я понимаю, нет способа преобразовать NSURLRequest или NSHTTPURLResponse в CFHTTPMessageRef (заголовок stackoverflow.com/questions/2861740/). Так что, к сожалению, я не могу использовать CFNetworking API с NSURLProtocol. - person Borys Verebskyi; 23.03.2016
comment
Если подумать об этом более внимательно, единственное жизнеспособное решение, которое я могу придумать, — это swizzled инициализатор в вашей категории и заставить swizzled метод захватить версию HTTP в связанное хранилище объектов и вызвать исходный инициализатор. Вам также понадобится собственный геттер/аксессор, чтобы вернуть значение (пользовательская часть будет считывать его обратно из связанного хранилища объектов), но тогда это может быть так же просто, как self.httpVersion. Я могу предоставить более подробную информацию, если хотите, но это должно быть довольно просто, если вы раньше занимались свизлом. - person fullofsquirrels; 28.03.2016
comment
Просто чтобы замкнуть цикл на этом, я попытался сделать то, что описал в своем предыдущем комментарии, и конструктор swizzled никогда не вызывается, что заставляет меня поверить, что либо NSHTTPURLResponse на самом деле является частью кластера классов, либо есть скрытый конструктор, используемый NSURLSessionTasks и им подобные. Итак, не говоря уже о нецелесообразности использования метода класса фреймворка, я не думаю, что из-за этого он на самом деле мог бы работать. - person fullofsquirrels; 06.04.2016
comment
Спасибо за ваши старания. Я тоже попробую поиграть со свизлингом, идея отличная. Возможно, я найду соответствующий частный конструктор, используя заголовки, созданные во время выполнения. В любом случае, я сделаю это после окончания отпуска. - person Borys Verebskyi; 06.04.2016

Согласно команде CFNetwork, по крайней мере, год назад не было практического способа получить эту информацию. На самом деле, глядя на анализ заголовков во время выполнения, я сомневаюсь, что они вообще сохраняются.

Если я прав, то с этого момента это также не влияет на поведение сетевого стека, поэтому вы можете сказать, что это «HTTP/999.99», и это не имеет значения.

person dgatwood    schedule 02.05.2016

Класс NSURLSessionTaskTransactionMetrics имеет свойство с именем networkProtocolName. Этот экземпляр класса является одним из элементов массива, который также является свойством с именем transactionMetrics, которое является членом NSURLSessionTaskMetrics, который является входным параметром с именем metrics в методе обратного вызова с именем ..didFinishCollectingMetrics:.., который является частью протокола NSURLSessionTaskDelegate.

e.g:

- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0)) {
    self.redirectCount = metrics.redirectCount;
    self.networkProtocolName = metrics.transactionMetrics.lastObject.networkProtocolName;
}
person Nikita    schedule 09.12.2019