PWA機能追加後にスマホで戻るボタンERR_FAILEDが発生する問題の解決方法

PWA機能追加後にスマホで戻るボタンERR_FAILEDが発生する問題の解決方法

PWA機能追加後にスマートフォンで戻るボタンERR_FAILEDエラーが発生する問題を表現した技術イラスト。スマホ画面にエラーメッセージ、周囲にService WorkerアイコンとPWAコードが浮かぶ

はじめに

今回はレーシングシミュレーターとはまたっく関係のない話ですが、WEBサイトの問題で苦労して解決した事があったので、今後同じような問題を抱えた方がいたら少しでも助けになればと思い書かせていただきます。

ECサイトの運営でサイトに2024年7月3日にPWA(Progressive Web App)機能を追加したところ、スマートフォンユーザーから「戻るボタンを押すとエラーが出る」という報告が相次ぎました。約26日間にわたって原因不明のまま続いていたこの問題の、困難な原因特定から解決までの全過程を、同じ問題で困っている方のために詳しく解説します。

発生していた問題

主要症状

  • スマートフォンで戻るボタンを押すとERR_FAILEDエラーが発生
  • 注文フローの途中で離脱するユーザーが増加
  • PWA「ホーム画面に追加」プロンプトが意図せず表示
  • PCブラウザでは軽微な影響のみ

影響範囲

  • 期間: 2024年7月3日〜2025年1月29日(約26日間継続)
  • 対象: 主にスマートフォンユーザー(Android/iPhone)
  • ビジネス影響: 購入完了率の低下、機会損失

困難を極めた原因調査過程

フェーズ1: サーバー設定を疑う

最初に疑ったのはサーバー側の設定問題でした。

調査した項目

# Apacheの設定確認
sudo apache2ctl configtest
sudo systemctl status apache2

# エラーログの確認
tail -f /var/log/apache2/error.log

# .htaccessの設定チェック
# URL書き換えルールの確認
# HTTPS設定の確認

権限問題の調査

# ディレクトリ権限の確認
ls -la /var/www/html/tmp/
chmod 755 /var/www/html/tmp/

# CGIスクリプトの権限確認
chmod 755 /path/to/cgi-bin/*.cgi

結果: サーバー設定は正常。権限問題も修正したが、戻るボタンエラーは継続。

フェーズ2: セッション管理システムを疑う

次に疑ったのはセッションIDや状態管理の問題でした。

CGIスクリプトのセッション処理調査

# CGI内のセッション処理を詳細チェック
my $session_id = $in{'_order'} || '';
my $sid = $in{'sid'} || '';

# セッションファイルの存在確認
if (!-e "/tmp/session_$session_id") {
    # セッションエラー処理
}

発見した問題と修正

# 問題のあったコード(未定義変数エラー)
if ($in{'_order'} eq '') {
    # 処理A
}

# 修正後のコード
if (!defined($in{'_order'}) || $in{'_order'} eq '') {
    # 処理A
}

結果: セッション関連のエラーは修正できたが、戻るボタンエラーは依然として発生。

フェーズ3: ブラウザ・デバイス固有問題を疑う

デバイス別PWAエラー発生状況の比較図。iPhone・Androidスマートフォンには赤いERR_FAILEDエラー画面、PCデスクトップには緑のOK正常画面を表示

User-Agent判定システムの調査

# User-Agent判定ロジックの確認
my $ua = $ENV{'HTTP_USER_AGENT'} || '';
if ($ua =~ /Mobile|Android|iPhone/) {
    # スマホ用HTMLを表示
    print "Location: /mobile/index.html\n\n";
} else {
    # PC用HTMLを表示
    print "Location: /desktop/index.html\n\n";
}

複数デバイスでのテスト

  • iPhone Safari: ERR_FAILED発生
  • Android Chrome: ERR_FAILED発生
  • PC Chrome (モバイルエミュレート): ERR_FAILED発生
  • PC Chrome (通常): 正常動作

結果: スマートフォン特有の問題であることは確認できたが、根本原因は不明。

フェーズ4: PWA機能が原因と判明(調査期間:数時間)

転機となった発見

ブラウザの開発者ツールで偶然、以下を発見:

Chrome DevTools > Application タブ > Service Workers
→ 「このサイトではService Workerが登録されています」

あれ?Service Workerなんて実装していない…

PWA関連ファイルの検索

# 2024年7月3日に追加されたファイルを検索
find /var/www/html -name "*.html" -newer /tmp/date_20240703 -exec grep -l "serviceWorker\|manifest" {} \;

# 結果
/var/www/html/index.html
/var/www/html/mobile/index.html

決定的な証拠の発見

HTMLファイル内で以下のコードを発見:

<!-- 2024年7月3日に追加されていたコード -->
<script>
if ('serviceWorker' in navigator) {
  // 空の処理だが、ブラウザはPWAとして認識していた
}
</script>

<link rel="apple-touch-icon" sizes="180x180" href="/ico/apple-touch-icon.png">
<!-- PWA関連のアイコン設定 -->

仮説の検証

  1. PWA関連コードを一時的にコメントアウト
  2. ブラウザキャッシュをクリア
  3. スマートフォンでテスト

戻るボタンが正常動作!

なぜPWA機能が原因だったのか

調査で判明した技術的原因

  1. 空のService Worker登録の影響
// 問題のコード
if ('serviceWorker' in navigator) {
  // 何も処理していないが、ブラウザはService Workerの存在を認識
  // → PWAモードで動作開始
  // → 戻るボタンの挙動がネイティブアプリ風に変更
  // → 適切なService Workerが無いためERR_FAILED
}
  1. beforeinstallpromptイベントの影響
window.addEventListener('beforeinstallprompt', (e) => {
  e.preventDefault();
  // → ブラウザがインストール可能PWAとして認識
  // → 通常のWebサイトとは異なるライフサイクル管理
  // → ナビゲーション処理で競合発生
});
  1. ブラウザの内部処理変更
  • 通常のWebサイト: history.back() → HTTP履歴ベースの戻る処理
  • PWA認識後: history.back() → アプリ内ナビゲーション処理を試行
  • Service Worker未実装 → ナビゲーション処理失敗 → ERR_FAILED

問題の原因(詳細技術解説)

PWA機能追加時のコード

問題の原因となっていたのは、以下のPWA関連コードでした:

1. Service Worker登録コード

<script>
if ('serviceWorker' in navigator) {
  // 空の処理だが、Service Workerの検出処理が動作していた
}
</script>

2. PWAインストール機能

<script>
let deferredPrompt;
window.addEventListener('beforeinstallprompt', (e) => {
  e.preventDefault();
  deferredPrompt = e;
});

document.querySelector('.install-pwa').addEventListener('click', (e) => {
  e.preventDefault();
  if (deferredPrompt) {
    deferredPrompt.prompt();
    deferredPrompt.userChoice.then((choiceResult) => {
      if (choiceResult.outcome === 'accepted') {
        console.log('ホーム画面に追加されました');
      } else {
        console.log('キャンセルされました');
      }
      deferredPrompt = null;
    });
  }
});

window.addEventListener('appinstalled', () => {
  console.log('PWAがインストールされました');
});
</script>

3. PWA用アイコン設定

<link rel="apple-touch-icon" sizes="180x180" href="/ico/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="192x192" href="/ico/android-chrome-192x192.png">
<link rel="icon" type="image/png" sizes="512x512" href="/ico/android-chrome-512x512.png">

4. PWAインストール用UI

<li><a href="#" class="install-pwa">ホーム画面に追加して簡単アクセス!</a></li>

なぜ戻るボタンでエラーが発生したのか

  1. Service WorkerとブラウザナビゲーションAPIの競合
    • 空のService Worker登録でも、ブラウザはPWAとして認識
    • 戻るボタンの動作がネイティブアプリ的な挙動に変更
    • 適切なService Workerが実装されていないため、ナビゲーション処理でエラー
  2. beforeinstallpromptイベントの影響
    • ブラウザがPWAインストール可能と判断
    • 通常のWebサイトとは異なるライフサイクル管理
    • 戻るボタン処理時の状態管理に問題

解決方法

PWA問題コードの修正前後比較。左側に問題のあるService Worker登録コード、右側に削除後の修正済みコードを並べて表示

手順1: 問題箇所の特定

まず、以下のコマンドでPWA関連コードを検索:

# PWA関連ファイルの検索
find /path/to/website -name "*.html" -exec grep -l "serviceWorker\|manifest\|beforeinstallprompt" {} \;

# アイコン関連の検索
grep -r "apple-touch-icon\|android-chrome" /path/to/website/

手順2: PWA関連コードの完全削除

HTMLファイルから削除するコード

❌ 削除対象1: Service Worker登録

<script>
if ('serviceWorker' in navigator) {
  // この部分を完全削除
}
</script>

❌ 削除対象2: PWAアイコン

<link rel="apple-touch-icon" sizes="180x180" href="/ico/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="192x192" href="/ico/android-chrome-192x192.png">
<link rel="icon" type="image/png" sizes="512x512" href="/ico/android-chrome-512x512.png">

❌ 削除対象3: PWAインストール用JavaScript

<script>
let deferredPrompt;
window.addEventListener('beforeinstallprompt', (e) => {
  // この部分を完全削除
});
// 関連するすべてのPWAインストール処理を削除
</script>

❌ 削除対象4: PWAインストールUI

<li><a href="#" class="install-pwa">ホーム画面に追加して簡単アクセス!</a></li>

保持すべきファイル(通常のファビコン)

✅ 残すべきコード

<link rel="icon" href="/favicon.ico">
<link rel="icon" type="image/png" sizes="32x32" href="/ico/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/ico/favicon-16x16.png">

手順3: 関連ファイルの削除

もし以下のファイルが存在する場合は削除:

# PWA関連ファイルの削除
rm /path/to/website/sw.js
rm /path/to/website/service-worker.js
rm /path/to/website/site.webmanifest
rm /path/to/website/manifest.json

手順4: ブラウザキャッシュのクリア

修正後は必ずキャッシュをクリア:

Chrome/Edgeの場合

  1. F12で開発者ツールを開く
  2. Networkタブ → “Disable cache” をチェック
  3. ページをリロード

強制的なキャッシュクリア

<!-- 一時的に追加(修正完了後は削除) -->
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">

修正後の確認項目

✅ チェックリスト

  • [ ] スマホの戻るボタンが正常動作する
  • [ ] PWAインストールプロンプトが表示されない
  • [ ] ブラウザアドレスバーにインストールアイコンが表示されない
  • [ ] 注文フローが最後まで完了する
  • [ ] 開発者ツールでService Workerエラーが出ない

デバッグ方法

Chrome DevToolsでの確認

1. F12 → Application タブ
2. Service Workers セクション
3. 登録されているService Workerがないことを確認
4. Manifest セクション
5. manifest.jsonが読み込まれていないことを確認

予防策・今後の対応

PWA実装時の注意点

1. 段階的な実装

// 正しいPWA実装例
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js')
    .then(registration => {
      console.log('SW registered: ', registration);
    })
    .catch(registrationError => {
      console.log('SW registration failed: ', registrationError);
    });
}

2. 適切なService Worker実装

// sw.js の基本実装例
self.addEventListener('install', event => {
  event.waitUntil(
    caches.open('v1').then(cache => {
      return cache.addAll([
        '/',
        '/styles.css',
        '/script.js'
      ]);
    })
  );
});

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request).then(response => {
      return response || fetch(event.request);
    })
  );
});

3. manifest.json の正しい設定

{
  "name": "あなたのアプリ名",
  "short_name": "アプリ",
  "start_url": "/",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#000000",
  "icons": [
    {
      "src": "/ico/android-chrome-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    }
  ]
}

監視・早期発見体制

1. エラー監視の実装

// エラー監視コード例
window.addEventListener('error', (e) => {
  console.error('Global error:', e.error);
  // エラー報告システムに送信
});

window.addEventListener('unhandledrejection', (e) => {
  console.error('Unhandled promise rejection:', e.reason);
  // エラー報告システムに送信
});

2. 定期的なテスト

  • 複数デバイス・ブラウザでの動作確認
  • ユーザビリティテストの実施
  • アクセス解析での異常値監視

PWAとは?

PWA(Progressive Web App)の基本概念

**PWA(Progressive Web App)**は、Webサイトをネイティブアプリのように動作させる技術です。Googleが2015年に提唱した概念で、以下の特徴を持ちます:

PWAの主要機能

✅ ホーム画面への追加(インストール機能)
✅ オフライン動作
✅ プッシュ通知
✅ バックグラウンド同期
✅ ネイティブアプリライクなUI/UX
✅ 高速な読み込み

PWAの技術要素

1. Service Worker

javascript
// Service Workerの基本実装例
self.addEventListener('install', event => {
  event.waitUntil(
    caches.open('app-v1').then(cache => {
      return cache.addAll([
        '/',
        '/styles.css',
        '/app.js'
      ]);
    })
  );
});

Service Workerの役割:

  • ネットワークリクエストの制御
  • キャッシュ管理
  • バックグラウンド処理
  • オフライン機能の実現

2. Web App Manifest

json
{
  "name": "My PWA App",
  "short_name": "PWA App",
  "start_url": "/",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#000000",
  "icons": [
    {
      "src": "/icon-192.png",
      "sizes": "192x192",
      "type": "image/png"
    }
  ]
}

3. HTTPS必須

PWAはセキュリティ上の理由から、HTTPS環境でのみ動作します。

PWAのメリット・デメリット

✅ メリット

  • アプリストア不要: 直接Webからインストール
  • クロスプラットフォーム: iOS/Android両対応
  • 軽量: ネイティブアプリより軽い
  • 自動更新: アプリストア経由不要
  • SEO効果: 検索エンジンでインデックス可能

❌ デメリット

  • iOS制限: iOSでは一部機能に制限
  • 複雑性: 実装・デバッグが複雑
  • ブラウザ依存: ブラウザサポートに依存
  • 既存サイトとの競合: 今回のような問題が発生する可能性

まとめ

PWA機能の追加は、既存のWebサイトの基本動作に大きな影響を与える可能性があります。特に以下の点に注意が必要です:

重要なポイント

  1. PWAは単純な機能追加ではない
    • ブラウザの基本動作を変更する
    • Service Workerは強力だが、適切な実装が必須
  2. 十分なテスト期間の確保
    • 複数デバイス・ブラウザでの検証
    • 実際のユーザーフローでのテスト
  3. 段階的リリースの重要性
    • いきなり全ユーザーに適用しない
    • A/Bテストや限定ユーザーでの先行テスト
  4. 監視体制の構築
    • リアルタイムエラー監視
    • ユーザーフィードバックの迅速な収集

今回の事例では、約6ヶ月間にわたってユーザビリティに影響を与えてしまいました。同じような問題を避けるため、PWA実装時は慎重な検証を行うことを強くお勧めします。

この記事が同じ問題で困っている方の助けになれば幸いです。


関連タグ: #PWA #ServiceWorker #ECサイト #スマートフォン #ブラウザ #JavaScript #WebDevelopment #TechTrouble

カテゴリー: iracing日記 パーマリンク