File size: 3,427 Bytes
23443f5
39eaa9c
266d361
 
 
 
23443f5
266d361
 
39eaa9c
266d361
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
610a87b
266d361
 
 
610a87b
266d361
 
 
610a87b
266d361
 
 
 
 
 
 
 
 
 
 
610a87b
266d361
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
610a87b
266d361
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39eaa9c
266d361
 
 
 
23443f5
39eaa9c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8" />
  <title>iframe + BlobでService Worker登録</title>
</head>
<body>
  <h1>通信ログ(親ページ)</h1>
  <div id="log"></div>

  <script>
    // iframe内で動くHTML(Service Worker登録用)
    const iframeHtml = `
<!DOCTYPE html>
<html lang="ja">
<head><meta charset="UTF-8"></head>
<body>
  <script>
    // Service Workerのコード(文字列)
    const swCode = \`
      self.addEventListener('fetch', event => {
        const { request } = event;
        event.respondWith(
          fetch(request).then(response => {
            // クライアントにログを送信
            self.clients.matchAll().then(clients => {
              clients.forEach(client => {
                client.postMessage({
                  type: 'log',
                  url: request.url,
                  status: response.status,
                  method: request.method
                });
              });
            });
            return response;
          }).catch(error => {
            self.clients.matchAll().then(clients => {
              clients.forEach(client => {
                client.postMessage({
                  type: 'error',
                  url: request.url,
                  message: error.message
                });
              });
            });
            throw error;
          })
        );
      });
    \`;

    // BlobでSWスクリプト作成
    const blob = new Blob([swCode], {type: 'application/javascript'});
    const swUrl = URL.createObjectURL(blob);

    if ('serviceWorker' in navigator) {
      navigator.serviceWorker.register(swUrl).then(() => {
        parent.postMessage({type: 'sw-registered'}, '*');
      }).catch(e => {
        parent.postMessage({type: 'sw-error', message: e.message}, '*');
      });

      // SWからのメッセージを親iframeへ中継
      navigator.serviceWorker.addEventListener('message', event => {
        parent.postMessage({type: 'sw-message', data: event.data}, '*');
      });
    }
  <\/script>
</body>
</html>
    `;

    // iframe用Blob URL作成
    const iframeBlob = new Blob([iframeHtml], {type: 'text/html'});
    const iframeUrl = URL.createObjectURL(iframeBlob);

    // iframe作成してDOMに追加
    const iframe = document.createElement('iframe');
    iframe.src = iframeUrl;
    iframe.style.width = '100%';
    iframe.style.height = '200px';
    document.body.appendChild(iframe);

    // ログ表示領域
    const logDiv = document.getElementById('log');

    // iframeからのpostMessage受信
    window.addEventListener('message', e => {
      if (!e.data) return;

      if (e.data.type === 'sw-registered') {
        logDiv.textContent += '✅ Service Worker登録完了\n';
      } else if (e.data.type === 'sw-error') {
        logDiv.textContent += '❌ Service Worker登録エラー: ' + e.data.message + '\n';
      } else if (e.data.type === 'sw-message') {
        const d = e.data.data;
        if (d.type === 'log') {
          logDiv.textContent += `🔵 [${d.method}] ${d.url}${d.status}\n`;
        } else if (d.type === 'error') {
          logDiv.textContent += `🔴 エラー: ${d.message} (${d.url})\n`;
        }
      }
    });

    // テストfetch(親ページから)
    fetch('https://jsonplaceholder.typicode.com/posts/1');
    fetch('https://httpstat.us/404');
  </script>
</body>
</html>