Netassist Blog

【HTTP/2】iPhone・MacでCSSが初回アクセスで読み込まれない

こんにちは!運用エンジニアのtuouraです。

以前NginxでのHTTP/2について記事を書きましたが、今回もHTTP/2に絡み、Apple系デバイスでのみCSSが崩れサイトが正常に表示出来なかった事象について、書いていこうと思います。

1.サイト構成について

サイト構成は、Amazonのロードバランサー(ALB)+SSL証明書、配下EC2インスタンスのApacheで接続を受けている状態でした。

症状としては、Windowsやandroidではどのブラウザでも表示が崩れないものの、Apple系のデバイスでは、ブラウザを変えても、なぜか初回のみCSSが読み込まれず、表示崩れが発生する現象が発生していました。

2.アクセス状況と原因の予測

アクセスログを見る限りは、iPhoneやMacBookでもCSSへのアクセスは来ており、サーバー側へのリクエストは正常に見えました。

またCSSはあくまでも初回のみ表示崩れが発生し、2回目以降は正常に表示される為、リクエスト先ALBやサーバー側のエラーというよりは、Apple系デバイスに関わる何らかの問題と予測されました。

調査を進めるうちに、どうやらApache2.4+mod_http2の利用の際の、「Upgradeヘッダ」がApple系デバイスに問題を発生させるらしい事が分かりました。

iOS 11, macOS Hight Sierra で The operation couldn’t be completed. Protocol error が出る場合の対処

iPhone does not open HTTPS site in Safari with error NSPOSIXErrorDomain:100

3.実際のサーバー側の挙動

当時のサーバー側の挙動を再現したものが以下です。

サーバー内でドメインのIPをローカルIPで指定してCurlでヘッダを見てみると、確かに「Upgrade: h2,h2c」がレスポンスヘッダで出力されています。

[ec2-user@tuoura-aws ~]$ curl -I http://xxxxxx/ --resolve xxxxxx:80:127.0.0.1
HTTP/1.1 200 OK
Date: Wed, 17 Mar 2021 03:37:45 GMT
Server: Apache/2.4.46 ()
Upgrade: h2,h2c
Connection: Upgrade
Last-Modified: Thu, 04 Feb 2021 15:35:22 GMT
ETag: "5-5ba8473ac705c"
Accept-Ranges: bytes
Content-Length: 5
Content-Type: text/html; charset=UTF-8

ただ、ApacheのMPMはデフォルトのPreforokの為、HTTP/2が利用出来る設定にはなっていません。

[ec2-user@tuoura-aws ~]$ httpd -V
Server version: Apache/2.4.46 ()
Server built: Aug 24 2020 18:54:20
Server's Module Magic Number: 20120211:93
Server loaded: APR 1.6.3, APR-UTIL 1.6.1
Compiled using: APR 1.6.3, APR-UTIL 1.6.1
Architecture: 64-bit
Server MPM: prefork
threaded: no
forked: yes (variable process count)
Server compiled with....
~略

その為、明示的にh2cをリクエストしても、サーバからは当然Upgradeレスポンスは返って来ません。

どうやらAmazonLinix2のApacheではデフォルトでmod_http2を読み込んでおり、実際にApacheでHTTP/2が利用可能かどうか関わらず、常にUpgradeヘッダを出力している様でした。

[ec2-user@tuoura-aws ~]$ curl -vI --http2 http://xxxxxx/ --resolve xxxxxx:80:127.0.0.1
* Added xxxxxx:80:127.0.0.1 to DNS cache
* Rebuilt URL to: xxxxxx/
* Hostname xxxxxx was found in DNS cache
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to xxxxxx (127.0.0.1) port 80 (#0)
> HEAD / HTTP/1.1
> Host: xxxxxx
> User-Agent: curl/7.61.1
> Accept: */*
> Connection: Upgrade, HTTP2-Settings
> Upgrade: h2c
> HTTP2-Settings: AAMAAABkAARAAAAAAAIAAAAA
>
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Date: Thu, 18 Mar 2021 01:36:38 GMT
Date: Thu, 18 Mar 2021 01:36:38 GMT
< Server: Apache/2.4.46 ()
Server: Apache/2.4.46 ()
< Last-Modified: Thu, 04 Feb 2021 15:35:22 GMT
Last-Modified: Thu, 04 Feb 2021 15:35:22 GMT
< ETag: "5-5ba8473ac705c"
ETag: "5-5ba8473ac705c"
< Accept-Ranges: bytes
Accept-Ranges: bytes
< Content-Length: 5
Content-Length: 5
< Content-Type: text/html; charset=UTF-8
Content-Type: text/html; charset=UTF-8

<
* Connection #0 to host xxxxxx left intact

また、ドメインのレコードはALBに設定しているので、通常のアクセスはALBに流れます。
ブラウザからHTTP/2でALBへ接続する際はh2、当然HTTPSアクセスになり、ALPNでh2接続が可能かは判断出来るので、そもそもレスポンスヘッダでUpgradeヘッダは不要です。

[ec2-user@tuoura-aws ~]# curl -Iv https://xxxxxx/
* Rebuilt URL to: https://xxxxxx/
*   Trying xxx.xxx.xxx.xxx...
* TCP_NODELAY set
* Connected to xxxxx (xxx.xxx.xxx.xxx) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server accepted to use h2
* Server certificate:
~略

4.サーバ上の対策

という訳で、邪魔していると思われるUpgradeヘッダを削除しようと思います。

実はUpgradeヘッダについてはBugzillaでも報告があり、対策として「Header unset Upgrade」でUpgradeヘッダ削除も可能な様だったのですが、今回、Apache側でHTTP/2接続を行う事が無い事もあり、httpd.confからHTTP/2プロトコルの記述を無効化しました。(※反映の為、ApacheはReloadしています。)

<IfModule mod_http2.c>
    Protocols h2 h2c http/1.1
</IfModule>

#<IfModule mod_http2.c>
#    Protocols h2 h2c http/1.1
#</IfModule>

これでUpgradeヘッダが出なくなり、iPhoneやMacからも、正常にページが表示される様になりました。

[ec2-user@tuoura-aws ~]$ curl -I http://xxxxxx/ --resolve xxxxxx:80:127.0.0.1
HTTP/1.1 200 OK
Date: Thu, 18 Mar 2021 02:08:16 GMT
Server: Apache/2.4.46 ()
Last-Modified: Thu, 04 Feb 2021 15:35:22 GMT
ETag: "5-5ba8473ac705c"
Accept-Ranges: bytes
Content-Length: 5
Content-Type: text/html; charset=UTF-8

また、HTTP/2自体はALB側で受ける為、ALBへのアクセスでそのままHTTP/2が利用が可能なままな事を確認しています。

[ec2-user@tuoura-aws ~]$ curl -I https://xxxxxx/
HTTP/2 200
date: Thu, 18 Mar 2021 02:12:08 GMT
content-type: text/html; charset=UTF-8
content-length: 5
server: Apache/2.4.46 ()
last-modified: Thu, 04 Feb 2021 15:35:22 GMT
etag: "5-5ba8473ac705c"
accept-ranges: bytes

5.まとめ

今回、同じブラウザでも利用OS環境の相違で挙動が変わった為、早い段階でApple系デバイスだけ動きが違うのでは・・・という予測が立てられました。

ただ、Appleではデバイス毎の仕様詳細を公開している訳では無い為、検証結果や先人の方達の記録からの推測で対応をしました。その為、本当にApple系デバイスではUpgradeヘッダが原因でアクセスが出来なくなるかは、実は分からないままです。

もし同様の現象に悩んでいる方がいらっしゃれば、参考までに読んで頂けると嬉しいです。

それではまた!

 
 

この記事を書いた人

tuoura

株式会社ネットアシスト

埼玉県民。
猫が好き。

運用エンジニアです。

Twitter  Facebook