サーバー送信イベント(SSE)の紹介
サーバー送信イベント(SSE)は、クライアントがHTTP接続を介して自動的にサーバーから更新を受け取ることを可能にするサーバープッシュ技術です。クライアント接続を確立した後にサーバーがデータ転送をイニシエイトする方法を記述しています。これは、メッセージの更新やブラウザクライアントへの連続データストリームの送信に一般的に使用され、JavaScript APIのEventSourceを通じてローカルのクロスブラウザストリームを強化することを目的としています。クライアントはこのAPIを使用して特定のURLを要求し、イベントストリームを受信することができます。HTML5の一部として、EventSource APIはWHATWGによって標準化されています。SSEのメディアタイプはtext/event-streamです。
注意:SSEとWebsocketの最大の違いは、SSEが一方向のサーバーからクライアントへのメッセージプッシュであるのに対し、Websocketは双方向のメッセージプッシュであることです。時には、ビジネス要件がそれほど複雑でない場合、SSEの一方向のメッセージプッシュが十分であることがあります。これは、ChatGPT AI会話で使用される技術に類似しています。
Fiber SSEの例
package main
import (
"bufio"
"fmt"
"log"
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cors"
"github.com/valyala/fasthttp"
)
// HTMLクライアントをシミュレートします。ここでは、実際のビジネスシナリオでは、フロントエンドがこれを実装します。
var index = []byte(`<!DOCTYPE html>
<html>
<body>
<h1>SSEメッセージ</h1>
<div id="result"></div>
<script>
if(typeof(EventSource) !== "undefined") {
var source = new EventSource("http://127.0.0.1:3000/sse");
source.onmessage = function(event) {
document.getElementById("result").innerHTML += event.data + "<br>";
};
} else {
document.getElementById("result").innerHTML = "申し訳ありませんが、お使いのブラウザはサーバー送信イベントをサポートしていません...";
}
</script>
</body>
</html>
`)
func main() {
// Fiberインスタンス
app := fiber.New()
// 任意のドメインからのアクセスを許可するCORS制約
app.Use(cors.New(cors.Config{
AllowOrigins: "*",
AllowHeaders: "Cache-Control",
AllowCredentials: true,
}))
// /パスにアクセスすると、まずフロントエンドページを返し、フロントエンドがバックエンドにSSEメッセージプッシュを開始するようにします。
app.Get("/", func(c *fiber.Ctx) error {
c.Response().Header.SetContentType(fiber.MIMETextHTMLCharsetUTF8)
return c.Status(fiber.StatusOK).Send(index)
})
// SSEメッセージプッシュアドレス
app.Get("/sse", func(c *fiber.Ctx) error {
// sse httpヘッダーを設定します。Content-Typeに注意してください。
c.Set("Content-Type", "text/event-stream")
c.Set("Cache-Control", "no-cache")
c.Set("Connection", "keep-alive")
c.Set("Transfer-Encoding", "chunked")
// メッセージのプッシュを開始します
c.Context().SetBodyStreamWriter(fasthttp.StreamWriter(func(w *bufio.Writer) {
fmt.Println("WRITER")
var i int
// クライアントにメッセージを継続的にプッシュすることをシミュレートします
for {
i++
msg := fmt.Sprintf("%d - 現在の時刻は %v", i, time.Now())
// writerとFprintf関数を使用してメッセージをクライアントにプッシュします。実際のビジネスシナリオでは、フロントエンドの処理の便宜のためにJSONテキストを送信することができます
fmt.Fprintf(w, "data: メッセージ: %s\n\n", msg)
fmt.Println(msg)
// 出力データをクライアントにフラッシュします
err := w.Flush()
if err != nil {
// ウェブブラウザでページを更新すると、新しいSSE接続が確立されますが、最後の接続のみが有効です。したがって、ここで不要な接続を閉じる必要があります
fmt.Printf("フラッシュ中にエラーが発生しました: %v. http接続を閉じています。\n", err)
break
}
time.Sleep(2 * time.Second)
}
}))
return nil
})
// サーバーを起動します
log.Fatal(app.Listen(":3000"))
}