Skip to content

Commit

Permalink
2024/07/26 時点の英語版に基づき更新
Browse files Browse the repository at this point in the history
  • Loading branch information
mfuji09 committed Sep 18, 2024
1 parent d7c2882 commit f93181f
Showing 1 changed file with 29 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
---
title: サーバー送信イベントの使用
slug: Web/API/Server-sent_events/Using_server-sent_events
l10n:
sourceCommit: 4f35a8237ee0842beb9cfef3354e05464ad7ce1a
---

{{DefaultAPISidebar("Server Sent Events")}}

[サーバー送信イベント](/ja/docs/Web/API/Server-sent_events) (Server-Sent Events) を使用するウェブアプリケーションの開発は簡単です。サーバー上でフロントエンドへイベントを流すために必要になるコードはわずかですが、クライアント側のコードは[ウェブソケット](/ja/docs/Web/API/WebSockets_API)で入ってくるイベントを扱う部分とほぼ同じ動作をします。これは単方向の接続ですので、クライアントからサーバーへイベントを送信することはできません。

## サーバからのイベントの受信
## サーバーからのイベントの受信

サーバー送信イベント API は {{domxref("EventSource")}} インターフェイスに含まれています。イベントを受け取るためにサーバへの接続を開始するには、新たな `EventSource` オブジェクトを作成し、イベントを生成するスクリプトの URI を指定します。例を挙げます。
サーバー送信イベント API は {{domxref("EventSource")}} インターフェイスに含まれています。

### `EventSource` インスタンスの作成

イベントを受け取るためにサーバーへの接続を開始するには、新たな `EventSource` オブジェクトを作成し、イベントを生成するスクリプトの URI を指定します。例を挙げます。

```js
const evtSource = new EventSource("ssedemo.php");
Expand All @@ -23,46 +29,51 @@ const evtSource = new EventSource("//api.example.com/ssedemo.php", {
});
```

### `message` イベントの待ち受け

イベントソースのインスタンスを起動したら、 {{domxref("EventSource.message_event", "message")}} イベントのハンドラーを取り付けて、サーバーからのメッセージを待ち受けすることができます。

```js
evtSource.onmessage = function (event) {
evtSource.onmessage = (event) => {
const newElement = document.createElement("li");
const eventList = document.getElementById("list");

newElement.textContent = "message: " + event.data;
newElement.textContent = `message: ${event.data}`;
eventList.appendChild(newElement);
};
```

このコードは入力メッセージ(すなわち `event` フィールドを持たない、サーバーからの通知)を受信して、メッセージのテキストを文書の HTML にあるリストへ追加します。
このコードは入力メッセージを受信して、メッセージのテキストを文書の HTML にあるリストへ追加します。

`addEventListener()` を使用してイベントを待ち受けすることもできます。
### カスタムイベントの待ち受け

`event` フィールドが定義されているサーバーからのメッセージは、`event` で指定された名前のイベントとして受信されます。例を示します。

```js
evtSource.addEventListener("ping", function (event) {
evtSource.addEventListener("ping", (event) => {
const newElement = document.createElement("li");
const eventList = document.getElementById("list");
const time = JSON.parse(event.data).time;
newElement.textContent = "ping at " + time;
newElement.textContent = `ping at ${time}`;
eventList.appendChild(newElement);
});
```

前のコードと似ていますが、`event` フィールドに "ping" が設定されたメッセージがサーバーから送られたときに、自動的に呼び出されることが異なります。こちらは `data` フィールドの JSON を解釈して、情報を出力します。
このコードは、サーバーが `event` フィールドを `ping` に設定したメッセージを送信するたびに呼び出されます。こちらは `data` フィールドの JSON を解釈して、情報を出力します。

> **警告:** **HTTP/2 上で使用されていない**場合、 SSE は開くことができる接続の最大数に制限を受けます。この制限は*ブラウザー単位*で設定されており、非常に小さい数 (6) に設定されているため、複数のタブを開くと特に痛みを伴う場合があります。この問題は、 [Chrome](https://bugs.chromium.org/p/chromium/issues/detail?id=275955) と [Firefox](https://bugzilla.mozilla.org/show_bug.cgi?id=906896) で「修正予定なし」と示されています。この制限はブラウザー + ドメインごとに設定されており、`www.example1.com` への SSE 接続をすべてのタブで 6 つ、 `www.example2.com` への SSE 接続をさらに 6 つ開くことができることを意味します([Stackoverflow](https://stackoverflow.com/questions/5195452/websockets-vs-server-sent-events-eventsource/5326159) によれば)。 HTTP/2 を使用する場合、同時に使用することができる *HTTP ストリーム*の最大数は、サーバーとクライアントの間で交渉が行われます(既定値は 100 です)。
> **警告:** **HTTP/2 上で使用されていない**場合、 SSE は開くことができる接続の最大数に制限を受けます。この制限は*ブラウザー単位*で設定されており、非常に小さい数 (6) に設定されているため、複数のタブを開くと特に痛みを伴う場合があります。この問題は、 [Chrome](https://crbug.com/275955) と [Firefox](https://bugzil.la/906896) で「修正予定なし」と示されています。この制限はブラウザー + ドメインごとに設定されており、`www.example1.com` への SSE 接続をすべてのタブで 6 つ、 `www.example2.com` への SSE 接続をさらに 6 つ開くことができることを意味します([Stackoverflow](https://stackoverflow.com/questions/5195452/websockets-vs-server-sent-events-eventsource/5326159) によれば)。 HTTP/2 を使用する場合、同時に使用することができる *HTTP ストリーム*の最大数は、サーバーとクライアントの間で交渉が行われます(既定値は 100 です)。

## サーバからのイベントの送信
## サーバーからのイベントの送信

イベントを送信するサーバー側のスクリプトは、 MIME タイプ `text/event-stream` で応答する必要があります。個々の通知は、 2 つの改行で終わるテキストのブロックとして送信されます。イベントストリームの形式について、詳しくは[イベントストリーム形式](#イベントストリーム形式)をご覧ください。

この例で使用している {{Glossary("PHP")}} は次の通りです。

```php
date_default_timezone_set("America/New_York");
header("Cache-Control: no-store");
header("X-Accel-Buffering: no");
header("Content-Type: text/event-stream");
header("Cache-Control: no-cache");

$counter = rand(1, 10);
while (true) {
Expand All @@ -82,12 +93,14 @@ while (true) {
$counter = rand(1, 10);
}

if (ob_get_contents()) {
ob_end_flush();
}
flush();

// クライアントが接続を中止したら(ページを閉じたら)ループから抜ける

if ( connection_aborted() ) break;
if (connection_aborted()) break;

sleep(1);
}
Expand All @@ -97,14 +110,14 @@ while (true) {
ループは接続状態にかかわらず実行し続けられますので、接続が閉じられたとき(例えばクライアントがページを閉じたとき)にループから脱出するためのチェックが含まれています。

> [!NOTE]
> この記事にあるコードを使用した完全な例が GitHub にあります。 [Simple SSE demo using PHP](https://github.com/mdn/dom-examples/tree/master/server-sent-events) を参照してください。
> この記事にあるコードを使用した完全な例が GitHub にあります。 [Simple SSE demo using PHP](https://github.com/mdn/dom-examples/tree/main/server-sent-events) を参照してください。
## エラー処理

問題が発生した場合(ネットワークのタイムアウトや[アクセス制御](/ja/docs/Web/HTTP/CORS)に関する問題など)は、エラーイベントが生成されます。これをプログラムで処理するには、 `onerror` コールバックを `EventSource` に実装してください。

```js
evtSource.onerror = function (err) {
evtSource.onerror = (err) => {
console.error("EventSource failed:", err);
};
```
Expand Down Expand Up @@ -135,7 +148,7 @@ evtSource.close();
- `data`
- : メッセージのデータフィールドです。 `EventSource``data:` で始まる、複数の連続した行を受け取ったときは、[それらを連結して](https://html.spec.whatwg.org/multipage/#dispatchMessage)各項目の間に改行文字を挿入します。末尾の改行は取り除かれます。
- `id`
- : [`EventSource`](/ja/docs/Server-sent_events/EventSource) オブジェクトの最後のイベント ID の値に設定するイベント ID です。
- : [`EventSource`](/ja/docs/Web/API/EventSource) オブジェクトの最後のイベント ID の値に設定するイベント ID です。
- `retry`
- : 再接続時間です。サーバーへの接続が切れた場合、ブラウザーは指定した時間だけ待ってから再接続を試みます。これは整数値でなければならず、再接続時間をミリ秒単位で指定します。整数値以外が指定された場合は、このフィールドは無視されます。

Expand Down

0 comments on commit f93181f

Please sign in to comment.