Belajar Gin - WebSocket, Streaming & SSE
Series/Belajar Gin/Episode 16
Episode 16 of 23

Belajar Gin - WebSocket, Streaming & SSE

Episode ini membangun komunikasi realtime: WebSocket dengan gorilla/websocket di handler Gin, Server-Sent Events dengan SSEvent, streaming upload dan download, serta use case notifikasi dan chat.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Sampai episode 15, pola komunikasi kita selalu request-response: klien bertanya, server menjawab. Episode 16 ini membuka arah baru: realtime. Kalian akan membedah WebSocket dengan gorilla/websocket di dalam handler Gin, Server-Sent Events (SSE) untuk notifikasi satu arah, streaming upload dan download, serta use case nyata seperti chat dan progress bar.

Mengapa penting? Aplikasi modern menuntut pembaruan langsung: notifikasi muncul tanpa refresh, chat terkirim dalam milidetik, dan progress upload tampak bergerak. WebSocket memberikan saluran dua arah, SSE memberikan saluran satu arah yang lebih sederhana, dan keduanya berjalan mulus di atas Gin.

Memahami WebSocket dan SSE

Perbedaan Dua Teknologi

  • WebSocket: koneksi TCP persisten dua arah. Klien dan server sama-sama bisa mengirim pesan kapan saja. Cocok untuk chat, game, dan kolaborasi realtime.
  • SSE: koneksi HTTP satu arah dari server ke klien. Server mendorong event, klien hanya mendengarkan. Jauh lebih sederhana, memakai HTTP biasa, dan otomatis terhubung ulang.
Kapan memakai yang mana
# dua arah, latensi rendah, duplex
websocket: chat, game, kolaborasi
 
# satu arah, sederhana, auto-reconnect
sse: notifikasi, feed harga, progress

Untuk sebagian besar notifikasi, SSE sudah cukup dan menghindari kompleksitas manajemen koneksi WebSocket di sisi klien.

WebSocket dengan gorilla/websocket

Install dan Upgrade Handler

Mulai dengan menginstall gorilla/websocket:

Install gorilla/websocket
go get github.com/gorilla/websocket
Handler WebSocket echo
var upgrader = websocket.Upgrader{
    CheckOrigin: func(r *http.Request) bool {
        return true
    },
}
 
func echoHandler(c *gin.Context) {
    conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
    if err != nil {
        return
    }
    defer conn.Close()
 
    for {
        _, msg, err := conn.ReadMessage()
        if err != nil {
            break
        }
        if err := conn.WriteMessage(websocket.TextMessage, msg); err != nil {
            break
        }
    }
}
 
r.GET("/ws", echoHandler)

upgrader.Upgrade(c.Writer, c.Request, nil) mengubah request HTTP menjadi koneksi WebSocket. Handler ini memantulkan (echo) setiap pesan yang diterima. Perhatikan CheckOrigin — di production, kembalikan false untuk domain tak dikenal demi mencegah koneksi lintas situs.

Chat Sederhana dengan Channel

Untuk menyebarkan pesan ke banyak klien, gunakan pola broadcast via channel:

Broadcast pesan
var broadcast = make(chan []byte, 256)
 
func reader(conn *websocket.Conn) {
    defer conn.Close()
    for {
        _, msg, err := conn.ReadMessage()
        if err != nil {
            break
        }
        broadcast <- msg
    }
}
 
func writer(conn *websocket.Conn) {
    for msg := range broadcast {
        if err := conn.WriteMessage(websocket.TextMessage, msg); err != nil {
            return
        }
    }
}

broadcast <- msg mengirim pesan ke channel yang dibaca semua writer. Setiap koneksi punya goroutine reader dan writer; writer menerima pesan dari channel bersama. Di production, tambahkan registry klien dan filter per ruangan, dan selalu pasang deadline read/write untuk membuang koneksi yang diam.

Server-Sent Events di Gin

SSEvent dan Streaming

Gin menyediakan c.SSEvent untuk menulis satu event:

SSE endpoint
func sseHandler(c *gin.Context) {
    c.Header("Content-Type", "text/event-stream")
    c.Header("Cache-Control", "no-cache")
    c.Header("Connection", "keep-alive")
 
    c.Stream(func(w io.Writer) bool {
        c.SSEvent("message", "tick pada " + time.Now().Format("15:04:05"))
        time.Sleep(1 * time.Second)
        return true
    })
}
 
r.GET("/events", sseHandler)

c.SSEvent("message", data) menulis event SSE dengan nama message. c.Stream menjalankan fungsi secara berulang selama mengembalikan true — ini pola streaming satu arah yang dibahas singkat di episode 7. Header text/event-stream memberi tahu browser bahwa respons akan bertahan lama.

Streaming Upload dan Download

Streaming Upload dari Body

File besar tidak perlu dimuat seluruhnya ke memori. Stream langsung dari body request ke file:

Streaming upload
func streamUploadHandler(c *gin.Context) {
    src := c.Request.Body
    defer src.Close()
 
    dst, err := os.Create("./storage/besar.bin")
    if err != nil {
        c.JSON(500, gin.H{"error": err.Error()})
        return
    }
    defer dst.Close()
 
    n, err := io.Copy(dst, src)
    if err != nil {
        c.JSON(500, gin.H{"error": err.Error()})
        return
    }
    c.JSON(200, gin.H{"bytes": n})
}

io.Copy(dst, src) memindahkan data dari request ke disk dengan buffer kecil, bukan menampung seluruh body. Kombinasikan dengan Content-Length untuk membatasi ukuran dan dengan middleware rate limit dari episode 14 agar upload tidak menyedot bandwidth.

Use Case: Notifikasi dan Chat

Notifikasi Keuangan

Contoh paling umum SSE adalah notifikasi: server mengirim event setiap kali ada perubahan status. Server tidak perlu menunggu klien bertanya — event didorong langsung saat status berubah, misalnya setelah order dibuat atau pembayaran diverifikasi. Implementasinya cukup endpoint SSE yang membaca channel status, persis pola broadcast di atas.

Chat dengan WebSocket

Untuk chat, pilih WebSocket karena membutuhkan komunikasi dua arah dengan latensi rendah. Setiap pesan masuk dibroadcast ke semua koneksi di ruangan yang sama. Karena model ini berjalan di banyak goroutine, terapkan disiplin dari episode 12: gunakan channel untuk berbagi data, mutex untuk registry klien, dan selalu tutup goroutine saat koneksi berakhir agar tidak bocor.

Penutup

Inti yang harus dibawa pulang:

  • WebSocket untuk komunikasi dua arah; SSE untuk dorongan satu arah.
  • upgrader.Upgrade mengubah handler Gin menjadi koneksi WebSocket.
  • Pola reader + writer dengan channel menangani broadcast ke banyak klien.
  • c.SSEvent dan c.Stream membangun endpoint SSE dalam beberapa baris.
  • io.Copy dari c.Request.Body memungkinkan streaming upload.
  • Set CheckOrigin, deadline, dan batas ukuran untuk keamanan koneksi.

Di episode 17 selanjutnya kita akan membedah testing & benchmark — unit test handler dengan httptest, gin.CreateTestContext, table-driven test, mocking service, serta benchmark route dengan testing.B untuk membandingkan alokasi dan latensi.