# IM **Repository Path**: su_zhenhui/im ## Basic Information - **Project Name**: IM - **Description**: 聊天应用 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-04-17 - **Last Updated**: 2026-04-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README <<<<<<< HEAD # IM 即时通讯系统(MVP) 基于 **Vue3 + Go + WebSocket + MySQL + Redis + Kafka** 的最小可用即时通讯原型。Docker Compose 一键启动。 ## 目录结构 ``` IM/ ├── backend/ # Go 后端 │ ├── cmd/server/ # 入口 │ ├── internal/ │ │ ├── auth/ # JWT │ │ ├── cache/ # Redis(在线状态 + 离线队列) │ │ ├── config/ # 环境变量配置 │ │ ├── db/ # MySQL 连接与迁移 │ │ ├── handler/ # HTTP + WebSocket 处理 │ │ ├── model/ # 数据模型 │ │ ├── mq/ # Kafka 生产者/消费者 │ │ ├── service/ # 业务逻辑 │ │ └── ws/ # WebSocket Hub / Client / 协议 │ ├── Dockerfile │ └── go.mod ├── frontend/ # Vue3 前端(不使用 TS) │ ├── src/ │ │ ├── api/ # axios 封装 │ │ ├── router/ │ │ ├── store/ # pinia │ │ ├── views/ # Login / Chat │ │ ├── ws.js # 自动重连 WebSocket 客户端 │ │ ├── App.vue │ │ ├── main.js │ │ └── styles.css │ ├── Dockerfile │ ├── nginx.conf │ ├── vite.config.js │ └── package.json ├── docker-compose.yml └── README.md ``` ## 快速启动(Docker) 需要 Docker Desktop。 ```bash docker compose up -d --build ``` 启动后: - 前端: http://localhost:8000 - 后端 REST/WS: http://localhost:8080 - MySQL: `localhost:3306`(用户 `im`/密码 `impass`,库 `im`) - Redis: `localhost:6379` - Kafka: `localhost:9092` 打开两个浏览器(或隐身窗口),分别注册两个账号,互相加好友即可聊天。 ## 本地开发(不使用 Docker) 1. 启动依赖(最快方式仍是 Docker): ```bash docker compose up -d mysql redis kafka ``` 2. 启动后端: ```bash cd backend go mod tidy go run ./cmd/server ``` 3. 启动前端: ```bash cd frontend npm install npm run dev ``` 访问 http://localhost:5173 (Vite 已配置 `/api` 与 `/ws` 代理到 `localhost:8080`) ## 核心特性 - **WebSocket 长连接**:`gorilla/websocket`,心跳保活 + 自动重连(前端指数退避) - **JWT 鉴权**:REST 用 `Authorization: Bearer`;WebSocket 通过 `?token=` 查询参数 - **Kafka 异步投递**:消息入队 → 消费者持久化到 MySQL → 通知在线接收方 / 入离线队列 - **至少一次投递 + 幂等**:`(from_user, client_msg_id)` 唯一索引;Kafka 手动提交 offset - **ACK 机制**: - 服务端 → 发送方:`ack`(包含 `server_msg_id` + 入库时间) - 服务端 → 接收方:`deliver` - 接收方 → 服务端:`ack`(投递确认,MVP 中仅用于标记) - **离线消息**:接收方离线时把 `server_msg_id` 推入 Redis `im:offline:` 列表,用户上线自动回放 - **多设备同步**:同一 uid 的多个 WS 连接都会收到 deliver;发送方其他设备也会收到自己消息的副本 - **在线状态**:Redis `im:online:`,TTL 2 分钟,每分钟续期 ## API 概览 ### REST | 方法 | 路径 | 说明 | |---|---|---| | POST | `/api/register` | `{username,password,nickname}` → `{user, token}` | | POST | `/api/login` | `{username,password}` → `{user, token}` | | GET | `/api/me` | 当前用户 | | GET | `/api/users/search?q=` | 搜索用户 | | GET | `/api/friends` | 好友列表 | | POST | `/api/friends` | `{friend_id}` 添加好友(双向) | | GET | `/api/messages?peer=&limit=50` | 历史消息 | ### WebSocket `/ws?token=` 帧格式(JSON): 发送消息(client → server): ```json { "type":"chat", "client_msg_id":"c_xxx", "to_user":2, "content":"hi", "msg_type":"text" } ``` 服务端 ACK(sender 收到): ```json { "type":"ack", "client_msg_id":"c_xxx", "server_msg_id":123, "from_user":1, "to_user":2, "created_at":1700000000000 } ``` 投递(receiver 或 sender 其他设备收到): ```json { "type":"deliver", "client_msg_id":"c_xxx", "server_msg_id":123, "from_user":1, "to_user":2, "content":"hi", "msg_type":"text", "created_at":1700000000000 } ``` 投递确认(receiver → server): ```json { "type":"ack", "client_msg_id":"c_xxx", "server_msg_id":123 } ``` ## 架构数据流 ``` ┌─────────┐ WebSocket ┌──────────────┐ Kafka ┌────────────┐ SQL ┌───────┐ │ Vue3 UI │ ───────────▶ │ Gateway (Go) │ ────────▶ │ Consumer │ ──────▶ │ MySQL │ │ │ ◀─── ack ─── │ + Hub │ ◀─ route ─│ (同进程) │ └───────┘ └─────────┘ └──────┬───────┘ │ online? Redis ▼ ┌──────────────┐ │ Redis │ 在线状态 + 离线队列 └──────────────┘ ``` MVP 中 Gateway 与 Consumer 在同一进程便于调试;生产环境可直接拆分(换 Kafka Consumer Group 即可水平扩展)。 ## 测试 ```bash cd backend go test ./... ``` 覆盖了: - `internal/auth`:JWT 生成/校验/非法 token - `internal/ws`:Hub 多设备投递与移除 继续补充(建议): - `service` 层使用 `go-sqlmock` 做单元测试 - 端到端:启动 compose 后用 `nodejs` 或 `k6` 模拟 WS 压测 ## 路线图(从 MVP → 生产级) 1. 网关独立:拆出独立的 `gateway` 服务,通过 gRPC 调用 `logic` 服务 2. 多网关路由:Redis 中 `online:` 记录节点 ID,跨节点投递用 Kafka/Redis pubsub 3. 可观测性:接入 Prometheus(`promhttp` + 自定义 counter/gauge)、Grafana Dashboard 4. 限流 / 熔断:gateway 每连接 QPS 限制;Kafka 消费端背压 5. 消息加密:客户端 E2E(X3DH/libsignal)或至少 TLS + 敏感字段 AES 6. 群聊、消息撤回、已读未读、消息类型扩展(图片/文件) 7. 单元测试覆盖率 80%+ 与集成测试 / k6 压测脚本 8. K8s Helm Chart,HPA 基于连接数/CPU ## 安全说明 MVP 已有: - 密码 bcrypt 存储 - JWT 签名鉴权 - WebSocket 鉴权(token 查询参数) - `from_user` 服务端强制覆盖(防伪造) - `client_msg_id` 幂等去重 生产需补: - HTTPS/WSS(在网关前放 nginx/traefik 终结 TLS) - `CheckOrigin` 严格校验(防 CSRF via WS) - 前端所有消息内容渲染用文本节点,避免 XSS(当前 Vue 的 `{{ }}` 已自动转义) - 速率限制与登录爆破防护 - CSP / SameSite / HttpOnly Cookie(如改用 cookie) ======= # IM #### 介绍 聊天应用 #### 软件架构 软件架构说明 #### 安装教程 1. xxxx 2. xxxx 3. xxxx #### 使用说明 1. xxxx 2. xxxx 3. xxxx #### 参与贡献 1. Fork 本仓库 2. 新建 Feat_xxx 分支 3. 提交代码 4. 新建 Pull Request #### 特技 1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md 2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) 3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) 6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) >>>>>>> 0dd516cc4c93dede29de9895796a742b09da680e