EC2でrailsアプリをpwa化しようとしたらsafariでServiceWorker responce error is nullが発生


どのような問題が発生したのか?

awsのec2サーバー上にrailsプロジェクトとapacheの環境を作りrailsで顧客管理ツールをpwa化しようとした際に、
iOS版 safari,OSX版 safariで

"サイトを開けません。The operation couldn't be completed. Protocol error" (NSPOSIXErrorDomain:100)

とのエラーが頻出する問題が発生した。

何度もリロードしてみると時々画面が表示されるが、画像やアイコンなどが全く表示されない。
コンソール画面を開いてみると大量の

"FetchEvent.respondWith received an error: Returned response is null"

というエラーが発生していた。

動作環境

  • AWS EC2
  • apache for ruby
  • Ruby on Rails 5.2.3
  • rails gem service worker

結局の原因

   「ec2内ロードバランサーのhttp/2通信が有効になっている」

結論に到るまで

コンソール上に表示された

"FetchEvent.respondWith received an error: Returned response is null"

というエラーをググると大概出てくるサイトはこういったものだが、根本的な解決ができなかった。

ここでハマってしまった私個人の原因は、
「safariのpwa対策は不完全」という先入観である。
確かにsafariのpwa対策はchromeよりも遅れているが、
エラーの原因をservice workerにあるのではないかと考え長い時間serviceworkerについての記事を巡っていた。
なにせ時々リクエストが成功する意味がわからない。

エラー文からすると
railsのgem,serviceworker-railsで生成されるjsファイル

/app/aseets/javascripts/serviceworker.js.erb
function onFetch(event) {
  event.respondWith(
    fetch(event.request).catch(function() {
      return caches.match(event.request).then(function(response) {
        if (response) {
          return response;
        }
        if (event.request.mode === 'navigate' ||
          (event.request.method === 'GET' && event.request.headers.get('accept').includes('text/html'))) {
          console.log('[Serviceworker]', "Fetching offline content", event);
          return caches.match('/offline.html');
        }
      })
    })
  );
}

ここの

if (response) {
 return responce;
}

が空になっているようだが、今まではこんなことがなかったし、
第一、開発用の別のec2サーバーでは同問題が全く起きていなかった。

serviceworkerの古いキャッシュかと思いブラウザのキャッシュを消してみてもダメ、
turbolinkとの兼ね合いの悪さかと思いrailsのturbolinksをオフにしてもダメ、

/app/views/application.html.erb
<head>
  ...
  <meta name="turbolinks-cache-control" content="no-cache">
</head>

これらでは効果がなかったので視野を広げることとし、サーバーの設定を確認してみることにした。

はじめに出てくる
 「"サイトを開けません。The operation couldn't be completed. Protocol error" (NSPOSIXErrorDomain:100)」
というエラーを調べてみるとこんなサイトが

iOS 11, macOS Hight Sierra で The operation couldn't be completed. Protocol error が出る場合の対処
Safariで発生するプロトコルエラー

safariだとapacheから独自レスポンスが乗っかり、クライアントではコネクトの失敗を返す「時がある」。
試しにロードバランサー => http/2 無効 にしてみると
全て治った。エラーも全く表示されない。

どうやらec2サーバーにアクセスするうちに何度か成功するが、
レスポンスが成功した時の不完全なキャッシュをserviceworkerが登録してしまい、次のリロードで不完全なキャッシュを元に描画され、
ファイルが見つからないというエラーを吐いていたということらしい。

これで真っさら解決した。

次に出てくる問題

ec2 LBのhttp/2通信を無効にしてしまったので、通信速度が懸念される。
+1%の高速化だけでもありがたい。
ただでさえrailsの速度はマイペースで、このツールでは膨大なデータのやりとりをするのに

なのでec2 LBのhttp/2は確保して、apache内の http/2通信の設定が必要になる。