Kết Nối & Xác Thực
Endpoint
wss://api.simplize.vn/v2/ws
Không cần query parameter. Yêu cầu TLS (wss://).
Trình Tự Handshake
Client Server
│ │
│──── TCP/WS connect ─────▶│
│◀─── connected ───────────│ ← thông số kết nối
│ │
│──── auth {token} ────────▶│ ← trong vòng 10 giây
│◀─── auth_ok ─────────────│
│ │
│ ... sẵn sàng ... │
Bước 1: Nhận connected
Server gửi ngay sau khi kết nối TCP thành công:
{
"type": "connected",
"sid": "550e8400-e29b-41d4-a716",
"ping_interval": 25000,
"ping_timeout": 20000,
"max_payload": 2097152
}
| Field | Kiểu | Mô tả |
|---|---|---|
sid | string | Connection ID dùng để debug |
ping_interval | number | Server gửi ping mỗi X ms |
ping_timeout | number | Thời gian chờ pong tối đa (ms) |
max_payload | number | Kích thước message tối đa (bytes) |
Bước 2: Gửi auth
{
"type": "auth",
"token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Phải gửi trong 10 giây sau khi nhận connected. Nếu không, server đóng với code 4001.
Bước 3: Nhận auth_ok
{
"type": "auth_ok"
}
Từ đây có thể gửi chat, subscribe, ...
Mã Lỗi Kết Nối
| Code | Nguyên nhân | Xử lý |
|---|---|---|
4001 | Timeout auth hoặc không gửi auth | Lấy token mới rồi connect lại |
4003 | Token không hợp lệ hoặc hết hạn | Refresh token rồi connect lại |
4008 | Không phản hồi heartbeat (zombie) | Tự động connect lại |
Heartbeat
Server gửi {"type": "ping"} mỗi 25 giây. Client phải phản hồi {"type": "pong"} trong 20 giây. Sau 2 lần miss liên tiếp, server đóng với code 4008.
Client cũng có thể chủ động gửi ping; server sẽ trả pong.
Ví Dụ: React.js
import { useEffect, useRef } from 'react'
function useAgentWS(token) {
const wsRef = useRef(null)
useEffect(() => {
const ws = new WebSocket('wss://api.simplize.vn/v2/ws')
wsRef.current = ws
ws.onmessage = (e) => {
const msg = JSON.parse(e.data)
if (msg.type === 'connected') {
ws.send(JSON.stringify({ type: 'auth', token }))
}
if (msg.type === 'auth_ok') {
console.log('Sẵn sàng')
}
if (msg.type === 'ping') {
ws.send(JSON.stringify({ type: 'pong' }))
}
if (msg.type === 'error') {
console.error('Lỗi:', msg.code, msg.message)
}
}
ws.onclose = (e) => {
if (e.code !== 4001 && e.code !== 4003) {
// Reconnect sau 3 giây
setTimeout(() => reconnect(), 3000)
}
}
return () => ws.close()
}, [token])
return wsRef
}
Ví Dụ: Flutter (Dart)
import 'dart:convert';
import 'package:web_socket_channel/web_socket_channel.dart';
class AgentWebSocket {
WebSocketChannel? _channel;
final String _token;
AgentWebSocket(this._token);
void connect() {
_channel = WebSocketChannel.connect(
Uri.parse('wss://api.simplize.vn/v2/ws'),
);
_channel!.stream.listen(
(data) => _handleMessage(jsonDecode(data as String)),
onDone: _handleDisconnect,
onError: (e) => print('WS Error: $e'),
);
}
void _handleMessage(Map<String, dynamic> msg) {
switch (msg['type']) {
case 'connected':
_send({'type': 'auth', 'token': _token});
break;
case 'auth_ok':
print('Sẵn sàng');
break;
case 'ping':
_send({'type': 'pong'});
break;
case 'error':
print('Lỗi: ${msg['code']} - ${msg['message']}');
break;
}
}
void _handleDisconnect() {
// Reconnect sau 3 giây
Future.delayed(const Duration(seconds: 3), connect);
}
void _send(Map<String, dynamic> data) {
_channel?.sink.add(jsonEncode(data));
}
void dispose() {
_channel?.sink.close();
}
}