-->

HTTP/2 Server Push in iOS 10

2020-07-20 04:27发布

问题:

I am trying to get server push working on iOS 10. I am working off of the Akamai HTTP/2 demo.

https://http2.akamai.com/demo

The following is my attempt at testing server push.

@interface ViewController () <NSURLSessionTaskDelegate>

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: self delegateQueue: [NSOperationQueue mainQueue]];

    NSString *displayArtUrl;
    for(int i=0; i<378; i++) {
        displayArtUrl = [NSString stringWithFormat:@"https://http2.akamai.com/demo/tile-%ld.png", (long)i];
        NSURL *url = [NSURL URLWithString:displayArtUrl];
        NSURLSessionDataTask *downloadTask = [defaultSession
                                              dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                              }];
        [downloadTask resume];
    }

}

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics {
    NSArray *fetchTypes = @[ @"Unknown", @"Network Load", @"Server Push", @"Local Cache" ];

    for(NSURLSessionTaskTransactionMetrics *transactionMetrics in [metrics transactionMetrics]) {

        NSLog(@"protocol[%@] reuse[%d] fetch:%@ - %@", [transactionMetrics networkProtocolName], [transactionMetrics isReusedConnection], fetchTypes[[transactionMetrics resourceFetchType]], [[transactionMetrics request] URL]);

        if([transactionMetrics resourceFetchType] == NSURLSessionTaskMetricsResourceFetchTypeServerPush) {
            NSLog(@"Asset was server pushed");
        }
    }
}

@end

Unfortunately, the logs show that the fetch type is always NSURLSessionTaskMetricsResourceFetchTypeNetworkLoad when I would expect it to be NSURLSessionTaskMetricsResourceFetchTypeServerPush sometimes. The server obviously supports it, as seen in the web demo.

...
2016-11-22 19:27:37.596205 HttpServerPush[2356:735927] protocol[h2] reuse[1] fetch:Network Load - https://http2.akamai.com/demo/tile-4.png
2016-11-22 19:27:37.596960 HttpServerPush[2356:735927] protocol[h2] reuse[1] fetch:Network Load - https://http2.akamai.com/demo/tile-5.png
2016-11-22 19:27:37.597877 HttpServerPush[2356:735927] protocol[h2] reuse[1] fetch:Network Load - https://http2.akamai.com/demo/tile-6.png
2016-11-22 19:27:37.603988 HttpServerPush[2356:735927] protocol[h2] reuse[1] fetch:Network Load - https://http2.akamai.com/demo/tile-1.png
2016-11-22 19:27:37.976911 HttpServerPush[2356:735927] protocol[h2] reuse[1] fetch:Network Load - https://http2.akamai.com/demo/tile-7.png
....

Has anyone had success with HTTP/2 server push on iOS 10? Is there something missing in the way the assets are being requested?

FYI, Charles Proxy seems to get in the way in this scenario. Enabling it causes iOS 10 to stop using HTTP/2 entirely.

...
2016-11-22 19:55:15.763 HttpServerPush[59822:1612935] protocol[http/1.1] reuse[1] fetch:Network Load - https://http2.akamai.com/demo/tile-8.png
2016-11-22 19:55:15.766 HttpServerPush[59822:1612935] protocol[http/1.1] reuse[1] fetch:Network Load - https://http2.akamai.com/demo/tile-11.png
2016-11-22 19:55:15.769 HttpServerPush[59822:1612935] protocol[http/1.1] reuse[1] fetch:Network Load - https://http2.akamai.com/demo/tile-9.png
2016-11-22 19:55:15.771 HttpServerPush[59822:1612935] protocol[http/1.1] reuse[1] fetch:Network Load - https://http2.akamai.com/demo/tile-12.png
...

回答1:

As far as I know, the Akamai demo page doesn't currently push any resource. A push occurs when a PUSH_PROMISE frame is sent by the server to the client. nghttp (installable via brew on Mac OS X: brew install nghttp2) can be used to display the frames sent by the server:

$ nghttp -nv 'https://http2.akamai.com/demo' | grep 'PUSH_PROMISE'
$

On the other hand, https://h2o.examp1e.net/, the home page of the H2O HTTP server, does push resources:

$ nghttp -nv 'https://h2o.examp1e.net' | grep 'PUSH_PROMISE'
[  0.587] recv PUSH_PROMISE frame <length=59, flags=0x04, stream_id=13>
[  0.587] recv PUSH_PROMISE frame <length=33, flags=0x04, stream_id=13>
[  0.588] recv PUSH_PROMISE frame <length=35, flags=0x04, stream_id=13>
[  0.588] recv PUSH_PROMISE frame <length=24, flags=0x04, stream_id=13>
[  0.588] recv PUSH_PROMISE frame <length=28, flags=0x04, stream_id=13>
$


回答2:

HTTP/2 Push is widely regarded to be broken in Safari. Do not regard this information as up to date, but last time I checked the browser would accept and sometimes use the pushed resources, while some other times it wouldn't.

ORIGINAL ANSWER:

I was about to answer you that HTTP/2 Push is not supported in iOS, but then I took a quick look to our page:

https://www.shimmercat.com

and waited for the connection stats to appear in the upper right corner. HTTP/2 Push is supported in iOS 10 !!