Raw Messages
Raw messages menyediakan saluran komunikasi level rendah antara frontend dan backend Anda, melewati sistem binding standar. Ini menukar kenyamanan demi kecepatan.
Kapan Menggunakan Raw Messages
Section titled “Kapan Menggunakan Raw Messages”Raw messages paling cocok untuk kasus edge yang ekstrem:
- Pembaruan frekuensi ultra-tinggi - Ribuan pesan per detik di mana setiap mikrodetik penting
- Protokol pesan kustom - Saat Anda memerlukan kontrol penuh atas format wire
Setup Backend
Section titled “Setup Backend”Konfigurasi RawMessageHandler di opsi aplikasi Anda:
package main
import ( "encoding/json" "fmt"
"github.com/wailsapp/wails/v3/pkg/application")
func main() { app := application.New(application.Options{ Name: "Raw Message Demo", Assets: application.AssetOptions{ Handler: application.BundledAssetFileServer(assets), }, RawMessageHandler: func(window application.Window, message string, originInfo *application.OriginInfo) { fmt.Printf("Raw message from window '%s': %s (origin: %+v)\n", window.Name(), message, originInfo.Origin)
// Proses pesan dan respons via event response := processMessage(message) window.EmitEvent("raw-response", response) }, })
app.Window.NewWithOptions(application.WebviewWindowOptions{ Title: "My App", Name: "main", })
app.Run()}
func processMessage(message string) map[string]any { // Logika pemrosesan pesan kustom Anda return map[string]any{ "received": message, "status": "processed", }}Signature Handler
Section titled “Signature Handler”RawMessageHandler func(window Window, message string, originInfo *application.OriginInfo)| Parameter | Tipe | Deskripsi |
|---|---|---|
window | Window | Window yang mengirim pesan |
message | string | Konten pesan mentah |
originInfo | *application.OriginInfo | Informasi origin tentang sumber pesan |
Struktur OriginInfo
Section titled “Struktur OriginInfo”type OriginInfo struct { Origin string TopOrigin string IsMainFrame bool}| Field | Tipe | Deskripsi |
|---|---|---|
Origin | string | URL origin dokumen yang mengirim pesan |
TopOrigin | string | URL origin level atas (mungkin berbeda dari Origin di iframe) |
IsMainFrame | bool | Apakah pesan berasal dari main frame |
Ketersediaan Spesifik Platform
Section titled “Ketersediaan Spesifik Platform”- macOS:
OrigindanIsMainFramedisediakan - Windows:
OrigindanTopOrigindisediakan - Linux: Hanya
Originyang disediakan
Validasi Origin
Section titled “Validasi Origin”Selalu verifikasi origin pesan masuk sebelum memprosesnya. Parameter originInfo menyediakan informasi keamanan kritis yang harus divalidasi untuk mencegah akses tidak sah.
Konten berbahaya, konten yang dikompromikan, atau skrip yang tidak diinginkan dapat mengirim raw message. Tanpa validasi origin, Anda mungkin memproses perintah dari sumber tidak tepercaya. Gunakan originInfo untuk memastikan pesan berasal dari sumber yang diharapkan.
Poin Validasi Utama
Section titled “Poin Validasi Utama”- Selalu periksa
Origin- Verifikasi origin cocok dengan sumber tepercaya yang diharapkan (biasanyawails://wailsatauhttp://wails.localhostuntuk asset lokal atau origin spesifik aplikasi Anda) - Validasi
IsMainFrame(macOS) - Waspadai jika pesan berasal dari iframe, karena ini mungkin menunjukkan konten tersemat dengan konteks keamanan berbeda - Gunakan
TopOrigin(Windows) - Verifikasi origin level atas saat menangani konten ber-frame - Tolak origin yang tidak diharapkan - Gagal dengan aman dengan menolak pesan dari origin yang tidak Anda izinkan secara eksplisit
Setup Frontend
Section titled “Setup Frontend”Kirim raw message menggunakan System.invoke():
<!DOCTYPE html><html><head> <script type="module"> import { System, Events } from '@wailsio/runtime'
// Kirim raw message document.getElementById('send').addEventListener('click', () => { const message = document.getElementById('input').value System.invoke(message) })
// Dengarkan respons Events.On('raw-response', (event) => { console.log('Response:', event.data) }) </script></head><body> <input type="text" id="input" placeholder="Enter message" /> <button id="send">Send</button></body></html>Menggunakan Bundle Siap Pakai
Section titled “Menggunakan Bundle Siap Pakai”Jika Anda tidak menggunakan npm, akses invoke melalui objek global wails:
<script type="module" src="/wails/runtime.js"></script><script> window.onload = function() { document.getElementById('send').onclick = function() { wails.System.invoke('my-message') } }</script>Pesan Terstruktur
Section titled “Pesan Terstruktur”Untuk data kompleks, serialisasi ke JSON:
Frontend
Section titled “Frontend”import { System } from '@wailsio/runtime'
const command = { action: 'update', payload: { id: 123, value: 'new value' }}
System.invoke(JSON.stringify(command))Backend
Section titled “Backend”RawMessageHandler: func(window application.Window, message string, originInfo *application.OriginInfo) { var cmd struct { Action string `json:"action"` Payload struct { ID int `json:"id"` Value string `json:"value"` } `json:"payload"` }
if err := json.Unmarshal([]byte(message), &cmd); err != nil { window.EmitEvent("error", err.Error()) return }
switch cmd.Action { case "update": // Tangani update result := handleUpdate(cmd.Payload.ID, cmd.Payload.Value) window.EmitEvent("update-complete", result) default: window.EmitEvent("error", "unknown action") }}Perbandingan Performa
Section titled “Perbandingan Performa”| Pendekatan | Overhead | Type Safety | Kasus Penggunaan |
|---|---|---|---|
| Service Bindings | Lebih tinggi | Penuh | Tujuan umum |
| Raw Messages | Minimal | Manual | Frekuensi tinggi, kritis performa |
Contoh Benchmark
Section titled “Contoh Benchmark”Raw messages dapat memproses jauh lebih banyak pesan per detik dibandingkan service bindings untuk payload sederhana:
// Raw message handler - overhead minimalRawMessageHandler: func(window application.Window, message string, originInfo *application.OriginInfo) { // Pemrosesan string langsung, tanpa reflection atau marshaling counter++}Contoh Lengkap
Section titled “Contoh Lengkap”Berikut contoh lengkap yang mengimplementasikan protokol perintah sederhana:
main.go
Section titled “main.go”package main
import ( "embed" "encoding/json" "fmt" "time"
"github.com/wailsapp/wails/v3/pkg/application")
//go:embed assetsvar assets embed.FS
type Command struct { Type string `json:"type"` Data json.RawMessage `json:"data"`}
func main() { app := application.New(application.Options{ Name: "Raw Message Demo", Assets: application.AssetOptions{ Handler: application.BundledAssetFileServer(assets), }, Mac: application.MacOptions{ ApplicationShouldTerminateAfterLastWindowClosed: true, }, RawMessageHandler: func(window application.Window, message string, originInfo *application.OriginInfo) { var cmd Command if err := json.Unmarshal([]byte(message), &cmd); err != nil { window.EmitEvent("error", map[string]string{"error": err.Error()}) return }
switch cmd.Type { case "ping": window.EmitEvent("pong", map[string]any{ "time": time.Now().UnixMilli(), "window": window.Name(), }) case "echo": var text string json.Unmarshal(cmd.Data, &text) window.EmitEvent("echo", text) default: window.EmitEvent("error", map[string]string{ "error": fmt.Sprintf("unknown command: %s", cmd.Type), }) } }, })
app.Window.NewWithOptions(application.WebviewWindowOptions{ Title: "Raw Message Demo", Name: "main", Width: 400, Height: 300, })
app.Run()}assets/index.html
Section titled “assets/index.html”<!DOCTYPE html><html><head> <title>Raw Message Demo</title> <style> body { font-family: sans-serif; padding: 20px; } button { margin: 5px; padding: 10px 20px; } #output { margin-top: 20px; padding: 10px; background: #f0f0f0; } </style></head><body> <h1>Raw Message Demo</h1>
<button id="ping">Ping</button> <button id="echo">Echo "Hello"</button>
<div id="output">Waiting for response...</div>
<script type="module"> import { System, Events } from '@wailsio/runtime'
const output = document.getElementById('output')
function send(type, data) { System.invoke(JSON.stringify({ type, data })) }
document.getElementById('ping').onclick = () => send('ping') document.getElementById('echo').onclick = () => send('echo', 'Hello')
Events.On('pong', (e) => { output.textContent = `Pong from ${e.data.window} at ${e.data.time}` })
Events.On('echo', (e) => { output.textContent = `Echo: ${e.data}` })
Events.On('error', (e) => { output.textContent = `Error: ${e.data.error}` }) </script></body></html>Praktik Terbaik
Section titled “Praktik Terbaik”Lakukan
Section titled “Lakukan”- Gunakan raw messages untuk jalur yang benar-benar kritis performa
- Implementasikan penanganan error yang benar di handler Anda
- Gunakan event untuk mengirim respons kembali ke frontend
- Pertimbangkan JSON untuk data terstruktur
- Jaga pemrosesan pesan tetap cepat agar tidak blocking
Jangan
Section titled “Jangan”- Gunakan raw messages saat service bindings sudah cukup
- Lupa memvalidasi pesan masuk
- Blocking di handler dengan operasi berjalan lama (gunakan goroutine)
- Abaikan parameter window saat respons perlu menarget window tertentu
Pertimbangan Multi-Window
Section titled “Pertimbangan Multi-Window”Parameter window mengidentifikasi window mana yang mengirim pesan, memungkinkan Anda untuk:
- Mengirim respons ke window yang benar
- Mengimplementasikan perilaku spesifik window
- Melacak sumber pesan untuk debugging
RawMessageHandler: func(window application.Window, message string, originInfo *application.OriginInfo) { // Respons hanya ke window pengirim window.EmitEvent("response", result)
// Atau broadcast ke semua window app.Event.Emit("broadcast", result)}Langkah Selanjutnya
Section titled “Langkah Selanjutnya”- Service Bindings - Pendekatan standar untuk sebagian besar aplikasi
- Events - Sistem event untuk komunikasi backend-ke-frontend
- Performance - Optimasi performa umum