Pesan Mentah
Implementasikan komunikasi khusus dari frontend ke backend untuk aplikasi yang sangat mementingkan performa
Pesan mentah menyediakan kanal komunikasi tingkat rendah antara frontend dan backend Anda dengan melewati sistem binding standar. Pendekatan ini mengorbankan kemudahan demi kecepatan.
Kapan Menggunakan Pesan Mentah
Pesan mentah paling sesuai untuk kasus ekstrem yang sangat jarang terjadi:
- Pembaruan berfrekuensi sangat tinggi - Ribuan pesan per detik ketika setiap mikrodetik sangat berarti
- Protokol pesan khusus - Ketika Anda memerlukan kendali penuh atas format data yang ditransmisikan
Penyiapan Backend
Konfigurasikan RawMessageHandler dalam 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)
// Process the message and respond via events
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 {
// Your custom message processing logic
return map[string]any{
"received": message,
"status": "processed",
}
}Signature Handler
RawMessageHandler func(window Window, message string, originInfo *application.OriginInfo)| Parameter | Tipe | Deskripsi |
|---|---|---|
window |
Window |
Jendela yang mengirim pesan |
message |
string |
Konten pesan mentah |
originInfo |
*application.OriginInfo |
Informasi asal tentang sumber pesan |
Struktur OriginInfo
type OriginInfo struct {
Origin string
TopOrigin string
IsMainFrame bool
}| Field | Tipe | Deskripsi |
|---|---|---|
Origin |
string |
URL asal dokumen yang mengirim pesan |
TopOrigin |
string |
URL asal tingkat teratas (mungkin berbeda dari Origin dalam iframe) |
IsMainFrame |
bool |
Apakah pesan berasal dari frame utama |
Ketersediaan Khusus Platform
- macOS:
OrigindanIsMainFramedisediakan - Windows:
OrigindanTopOrigindisediakan - Linux: Hanya
Originyang disediakan
Validasi Asal
Selalu verifikasi asal pesan masuk sebelum memprosesnya. Parameter originInfo menyediakan informasi keamanan penting yang harus divalidasi untuk mencegah akses tanpa izin. Konten berbahaya, konten yang telah disusupi, atau skrip yang tidak dimaksudkan dapat mengirim pesan mentah. Tanpa validasi asal, Anda mungkin memproses perintah dari sumber yang tidak tepercaya. Gunakan originInfo untuk memastikan pesan berasal dari sumber yang diharapkan.
Poin Validasi Utama
- Selalu periksa
Origin- Pastikan asal cocok dengan sumber tepercaya yang Anda harapkan (biasanyawails://wailsatauhttp://wails.localhostuntuk aset lokal atau asal khusus aplikasi Anda) - Validasi
IsMainFrame(macOS) - Perhatikan jika pesan berasal dari iframe karena hal ini dapat menunjukkan konten tersemat dengan konteks keamanan yang berbeda - Gunakan
TopOrigin(Windows) - Verifikasi asal tingkat teratas saat menangani konten dalam frame - Tolak asal yang tidak diharapkan - Terapkan kegagalan yang aman dengan menolak pesan dari asal yang tidak Anda izinkan secara eksplisit
Penyiapan Frontend
Kirim pesan mentah menggunakan System.invoke():
<!DOCTYPE html>
<html>
<head>
<script type="module">
import { System, Events } from '@wailsio/runtime'
// Send raw message
document.getElementById('send').addEventListener('click', () => {
const message = document.getElementById('input').value
System.invoke(message)
})
// Listen for response
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
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
Untuk data kompleks, lakukan serialisasi ke JSON:
Frontend
import { System } from '@wailsio/runtime'
const command = {
action: 'update',
payload: {
id: 123,
value: 'new value'
}
}
System.invoke(JSON.stringify(command))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":
// Handle update
result := handleUpdate(cmd.Payload.ID, cmd.Payload.Value)
window.EmitEvent("update-complete", result)
default:
window.EmitEvent("error", "unknown action")
}
}Perbandingan Performa
| Pendekatan | Overhead | Keamanan Tipe | Kasus Penggunaan |
|---|---|---|---|
| Binding Layanan | Lebih Tinggi | Penuh | Tujuan umum |
| Pesan Mentah | Minimal | Manual | Frekuensi tinggi, kritis terhadap performa |
Contoh Tolok Ukur
Untuk payload sederhana, pesan mentah dapat memproses jauh lebih banyak pesan per detik dibandingkan binding layanan:
// Raw message handler - minimal overhead
RawMessageHandler: func(window application.Window, message string, originInfo *application.OriginInfo) {
// Direct string processing, no reflection or marshaling
counter++
}Contoh Lengkap
Berikut contoh lengkap yang mengimplementasikan protokol perintah sederhana:
main.go
package main
import (
"embed"
"encoding/json"
"fmt"
"time"
"github.com/wailsapp/wails/v3/pkg/application"
)
//go:embed assets
var 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
<!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
Lakukan
- Gunakan pesan mentah untuk jalur yang benar-benar kritis terhadap performa
- Terapkan penanganan kesalahan yang tepat di handler Anda
- Gunakan event untuk mengirim respons kembali ke frontend
- Pertimbangkan JSON untuk data terstruktur
- Pastikan pemrosesan pesan tetap cepat agar tidak memblokir
Jangan Lakukan
- Jangan gunakan pesan mentah jika binding layanan sudah memadai
- Jangan lupa memvalidasi pesan yang masuk
- Jangan memblokir handler dengan operasi yang berjalan lama (gunakan goroutine)
- Jangan abaikan parameter window ketika respons perlu ditujukan ke window tertentu
Pertimbangan Multi-Window
Parameter window mengidentifikasi window yang mengirim pesan, sehingga Anda dapat:
- Mengirim respons ke window yang tepat
- Menerapkan perilaku khusus untuk setiap window
- Melacak sumber pesan untuk debugging
RawMessageHandler: func(window application.Window, message string, originInfo *application.OriginInfo) {
// Respond only to the sending window
window.EmitEvent("response", result)
// Or broadcast to all windows
app.Event.Emit("broadcast", result)
}Langkah Berikutnya
- Binding Layanan - Pendekatan standar untuk sebagian besar aplikasi
- Event - Sistem event untuk komunikasi dari backend ke frontend
- Performa - Pengoptimalan performa secara umum