193 行
3.3 KiB
Markdown
193 行
3.3 KiB
Markdown
|
|
# WebSocket 协议文档
|
|||
|
|
|
|||
|
|
XuqmGroup IM 使用 **STOMP over WebSocket** 协议进行实时消息通信。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 连接地址
|
|||
|
|
|
|||
|
|
| 环境 | 地址 |
|
|||
|
|
|------|------|
|
|||
|
|
| 演示环境 | `wss://dev.xuqinmin.com/ws/im` |
|
|||
|
|
| 生产环境 | 由租户平台分配 |
|
|||
|
|
|
|||
|
|
连接时需携带 `token` 参数:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
wss://dev.xuqinmin.com/ws/im?token={userSig}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 心跳机制
|
|||
|
|
|
|||
|
|
客户端在 STOMP CONNECT 帧中声明心跳:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
CONNECT
|
|||
|
|
accept-version:1.2
|
|||
|
|
heart-beat:0,0
|
|||
|
|
host:dev.xuqinmin.com
|
|||
|
|
Authorization:Bearer {token}
|
|||
|
|
|
|||
|
|
\x00
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> 当前服务端不强制心跳,客户端可依赖 WebSocket 原生 `onclose`/`onerror` 检测断线。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 消息格式(STOMP)
|
|||
|
|
|
|||
|
|
### CONNECT 帧
|
|||
|
|
|
|||
|
|
客户端建立 WebSocket 连接后,发送 STOMP CONNECT:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
CONNECT
|
|||
|
|
accept-version:1.2
|
|||
|
|
heart-beat:0,0
|
|||
|
|
host:dev.xuqinmin.com
|
|||
|
|
Authorization:Bearer {token}
|
|||
|
|
|
|||
|
|
\x00
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### CONNECTED 帧
|
|||
|
|
|
|||
|
|
服务端鉴权通过后返回:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
CONNECTED
|
|||
|
|
version:1.2
|
|||
|
|
|
|||
|
|
\x00
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### SUBSCRIBE 帧
|
|||
|
|
|
|||
|
|
订阅个人消息队列(自动执行):
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
SUBSCRIBE
|
|||
|
|
id:sub-1
|
|||
|
|
destination:/user/queue/messages
|
|||
|
|
|
|||
|
|
\x00
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
订阅群消息:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
SUBSCRIBE
|
|||
|
|
id:sub-2
|
|||
|
|
destination:/topic/group/{groupId}
|
|||
|
|
|
|||
|
|
\x00
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### SEND 帧 — 发送消息
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
SEND
|
|||
|
|
destination:/app/chat.send
|
|||
|
|
content-type:application/json
|
|||
|
|
|
|||
|
|
{"appId":"ak_demo_chat","messageId":"...","toId":"user_002","chatType":"SINGLE","msgType":"TEXT","content":"Hello"}
|
|||
|
|
\x00
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### SEND 帧 — 撤回消息
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
SEND
|
|||
|
|
destination:/app/chat.revoke
|
|||
|
|
content-type:application/json
|
|||
|
|
|
|||
|
|
{"appId":"ak_demo_chat","messageId":"..."}
|
|||
|
|
\x00
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### SEND 帧 — 同步离线消息
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
SEND
|
|||
|
|
destination:/app/chat.sync
|
|||
|
|
content-type:application/json
|
|||
|
|
|
|||
|
|
{"appId":"ak_demo_chat"}
|
|||
|
|
\x00
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### MESSAGE 帧 — 接收消息
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
MESSAGE
|
|||
|
|
destination:/user/queue/messages
|
|||
|
|
message-id:...
|
|||
|
|
|
|||
|
|
{"id":"...","fromId":"user_002","toId":"user_001","chatType":"SINGLE","msgType":"TEXT","content":"Hello","status":"SENT","createdAt":1715000000000}
|
|||
|
|
\x00
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### ERROR 帧
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
ERROR
|
|||
|
|
message:Unauthorized
|
|||
|
|
|
|||
|
|
Unauthorized
|
|||
|
|
\x00
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 订阅路径
|
|||
|
|
|
|||
|
|
| 路径 | 说明 |
|
|||
|
|
|------|------|
|
|||
|
|
| `/user/queue/messages` | 个人消息队列(登录后自动订阅)|
|
|||
|
|
| `/topic/group/{groupId}` | 群消息频道 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 服务端配置
|
|||
|
|
|
|||
|
|
基于 Spring WebSocket + STOMP:
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
@Configuration
|
|||
|
|
@EnableWebSocketMessageBroker
|
|||
|
|
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
|
|||
|
|
@Override
|
|||
|
|
public void configureMessageBroker(MessageBrokerRegistry registry) {
|
|||
|
|
registry.enableSimpleBroker("/topic", "/queue");
|
|||
|
|
registry.setApplicationDestinationPrefixes("/app");
|
|||
|
|
registry.setUserDestinationPrefix("/user");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
|||
|
|
registry.addEndpoint("/ws/im")
|
|||
|
|
.setAllowedOriginPatterns("*")
|
|||
|
|
.withSockJS();
|
|||
|
|
registry.addEndpoint("/ws/im")
|
|||
|
|
.setAllowedOriginPatterns("*");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 自定义客户端接入
|
|||
|
|
|
|||
|
|
如果业务方不使用官方 SDK,可按以下流程自建客户端:
|
|||
|
|
|
|||
|
|
1. 通过 `wss://host/ws/im?token=xxx` 建立 WebSocket
|
|||
|
|
2. 发送 STOMP CONNECT 帧(携带 `Authorization: Bearer {token}`)
|
|||
|
|
3. 收到 CONNECTED 后,订阅 `/user/queue/messages`
|
|||
|
|
4. 发送消息时构造 STOMP SEND 帧,`destination: /app/chat.send`
|
|||
|
|
5. 收到服务端 MESSAGE 帧后解析 JSON body
|
|||
|
|
|
|||
|
|
[→ Server API 文档 →](./api)
|