AI编程的发展让我很惶恐。我不知道做什么,不知道未来在哪里。但是我知道,我现在不能停下来。因为我不想被淘汰...
给前端工程师的后端入门地图:Rust + Flutter 即时聊天工具
你是谁:已经会前端,理解组件、状态、请求接口、构建工具,现在要用 Flutter + Rust 做一个即时聊天工具。
本文目标:用前端熟悉的方式理解后端要学什么、Java / Rust 和前端的差异,以及数据库、Redis、Apollo、消息队列等组件分别是什么意思。
1. 先建立一张全局图
一个 IM(即时聊天)系统不是只有「发一条消息」这么简单。它通常至少包含这些部分:
flowchart LR
Client[Flutter 客户端] -->|HTTP 登录/拉历史| API[后端 HTTP API]
Client -->|WebSocket 长连接| Gateway[实时连接网关]
API --> Auth[鉴权与用户服务]
Gateway --> Msg[消息服务]
Msg --> DB[(数据库)]
Msg --> Redis[(Redis)]
Msg --> MQ[消息队列]
API --> Config[Apollo/配置中心]
Gateway --> Config
MQ --> Worker[异步任务 Worker]
Worker --> Push[离线推送/审核/通知]
用前端语言理解:
| 组件 | 前端类比 | 后端里真正负责的事 |
|---|---|---|
| Flutter 客户端 | React/Vue 页面 + App 状态 | 展示聊天列表、输入消息、维护本地 UI 状态。 |
| Flutter 客户端 | React/Vue 页面 + App 状态 | 展示聊天列表、输入消息、维护本地 UI 状态。 |
| HTTP API | 你平时调用的 REST 接口 | 登录、注册、查用户、拉历史消息、上传资料。 |
| WebSocket 网关 | 一个长期不断开的 fetch | 实时收发消息、在线状态、输入中、已读回执。 |
| 数据库 | 持久化版的全局 store | 长期保存用户、好友关系、群、消息记录。 |
| Redis | 超高速临时 store / 内存缓存 | 在线状态、验证码、限流计数、热点数据、短期会话。 |
| 消息队列 | 异步事件总线 | 把“发消息后还要做的事”异步化,例如离线推送。 |
| Apollo 配置中心 | 远程 .env + Feature Flag | 动态改配置,不必每次重新发版。 |
| Worker | 后台任务脚本 | 消费队列,做推送、审核、统计、补偿任务。 |
2. 前端、后端、数据库到底怎么分工
2.1 前端负责「体验」
前端更接近:
- 页面布局、交互、动画;
- 本地状态管理;
- 调用接口;
- 展示 loading / error / empty;
- 缓存少量本地数据;
- 处理弱网、重试、断线提示。
前端状态通常是「用户当前正在看的状态」。它可以丢,可以重新拉。
2.2 后端负责「规则和事实」
后端更接近:
- 判断用户是谁;
- 判断用户有没有权限;
- 校验请求是否合法;
- 写入数据库;
- 保证消息 ID、顺序、去重;
- 给在线用户实时投递;
- 给离线用户后续补发或推送;
- 记录日志,方便排查问题。
后端保存的是「系统承认的事实」。例如一条消息是否发送成功,最终以后端落库为准,不以后端返回前的 UI 乐观状态为准。
2.3 数据库负责「长期事实」
数据库不是后端本身,而是后端依赖的一个存储系统。
前端可以把数据放在 state、localStorage、IndexedDB 里;但这些都是用户设备上的数据。后端数据库是服务端统一保存的数据来源。
比如 IM 里:
| 数据 | 应该放哪里 | 原因 |
|---|---|---|
| 用户账号 | 数据库 | 需要长期保存。 |
| 密码哈希 | 数据库 | 需要安全保存,不能明文。 |
| 好友关系 | 数据库 | 是业务事实。 |
| 群成员 | 数据库 | 是权限判断依据。 |
| 历史消息 | 数据库 | 用户换设备也要能查。 |
| 用户是否在线 | Redis | 高频变化,不适合作为长期事实。 |
| 验证码 | Redis | 几分钟过期。 |
| 当前 WebSocket 连接在哪台机器 | Redis / 内存 | 临时路由信息。 |
3. Java、Rust、前端的学习差异
3.1 三者写代码时的关注点
| 维度 | 前端 JS/TS | Java 后端 | Rust 后端 |
|---|---|---|---|
| 主要运行位置 | 浏览器 / App | JVM 进程 | 原生服务进程 |
| 典型框架 | React、Vue、Flutter | Spring Boot | Axum、Actix Web |
| 包管理 | npm、pnpm | Maven、Gradle | Cargo |
| 配置文件 | package.json | pom.xml / build.gradle | Cargo.toml |
| 类型系统 | TS 是编译期辅助,运行时仍是 JS | 强类型,运行在 JVM | 强类型,编译成机器码 |
| 内存管理 | JS 引擎 GC | JVM GC | 无 GC,所有权模型 |
| 错误处理 | try/catch、Promise reject | 异常、错误码 | Result、Option、? |
| 并发模型 | 事件循环、Promise | 线程池、虚拟线程、异步框架 | Tokio async、任务、通道 |
| 常见优势 | 开发 UI 快 | 企业生态成熟 | 性能、内存、安全边界强 |
| 常见门槛 | 浏览器兼容、状态复杂 | 框架厚、概念多 | 所有权、生命周期、异步边界 |
3.2 用前端经验理解 Java
Java 后端常见组合是:
Spring Boot + MySQL/PostgreSQL + Redis + MQ + 配置中心
你可以粗略类比为:
| Java 后端 | 前端类比 |
|---|---|
| Spring Boot | Next.js / Nuxt 这种全家桶框架 |
| Controller | API Route / 路由处理函数 |
| Service | 业务逻辑层,类似抽出来的业务 hooks/service |
| Repository / Mapper | 数据访问层,专门查数据库 |
| DTO | 前后端传输的数据结构 |
| Entity | 数据库表对应的对象 |
| Bean / IoC | 框架帮你创建并注入模块实例 |
Java 的好处是资料多、企业案例多、组件成熟;缺点是框架概念比较厚,初学时容易被注解、分层、配置淹没。
3.3 用前端经验理解 Rust
Rust 后端常见组合是:
Axum + Tokio + SQLx/SeaORM + PostgreSQL + Redis
你可以粗略类比为:
| Rust 后端 | 前端类比 |
|---|---|
| Cargo | pnpm/npm + 构建工具 |
| Axum 路由 | Express / API Route |
| Handler | 接口处理函数 |
| Extractor | 从请求里取 path、query、body、header |
serde | JSON 序列化/反序列化工具 |
Result<T, E> | 明确的成功/失败返回 |
Option<T> | 明确的 T | null |
| Tokio | 后端异步运行时,类似更底层的事件循环 |
Rust 的好处是性能好、类型严、适合长连接和高并发;缺点是入门期会被所有权、借用、生命周期卡住。
4. 后端必须学习的核心技能
4.1 HTTP API
这是后端入门第一层。
你需要理解:
GET / POST / PUT / DELETE;- URL、Query、Header、Body;
- JSON;
- 状态码:
200、400、401、403、404、500; - REST API;
- CORS;
- 接口版本;
- 请求幂等性。 前端类比:你以前只是调用 API,现在你要设计 API。
4.2 WebSocket
IM 必须重点学 WebSocket。
HTTP 更像「问一次,答一次」;WebSocket 更像「建立一条一直开着的电话线」。
IM 里 WebSocket 常处理:
- 用户上线;
- 服务端主动推新消息;
- 客户端发送消息;
- 心跳;
- 断线重连;
- 消息 ACK;
- 已读回执;
- 输入中状态。
需要特别注意:WebSocket 连接是有状态的。你的后端要知道「这个用户当前连接在哪台服务器上」。
4.3 鉴权与权限
后端要回答两个问题:
- 你是谁?
- 你能不能做这件事?
常见概念:
| 名词 | 含义 |
|---|---|
| 登录 | 用户证明自己身份。 |
| Token | 登录成功后发给客户端的凭证。 |
| JWT | 一种常见 token 格式,里面可带用户信息和过期时间。 |
| Session | 服务端保存登录状态,客户端只拿 session id。 |
| RBAC | 基于角色的权限控制。 |
| 密码哈希 | 密码不能明文入库,要用 Argon2、bcrypt 等算法处理。 |
前端可以隐藏按钮,但真正的权限必须由后端判断。
4.4 数据库与 SQL
先学关系型数据库,例如 PostgreSQL 或 MySQL。
你需要理解:
- 表、行、列;
- 主键;
- 外键;
- 索引;
- 事务;
- SQL;
- 数据迁移;
- 连接池;
- 慢查询。
IM 里可能有这些表:
| 表 | 存什么 |
|---|---|
users | 用户账号、昵称、头像。 |
conversations | 单聊/群聊会话。 |
conversation_members | 会话成员。 |
messages | 消息正文、发送人、时间、序号。 |
message_receipts | 已读、送达状态。 |
4.5 Redis
Redis 是内存型数据存储,速度很快,通常用于缓存和临时状态。
它不等于数据库,虽然它也能存数据。区别是:
| 维度 | 数据库 | Redis |
|---|---|---|
| 主要用途 | 长期保存业务事实 | 缓存、临时状态、高频读写 |
| 数据位置 | 主要面向磁盘持久化 | 主要在内存 |
| 典型数据 | 用户、订单、消息历史 | 验证码、在线状态、限流计数 |
| 查询能力 | SQL、复杂查询、事务能力强 | Key-Value 操作快 |
| 丢失影响 | 通常不能丢 | 设计上应尽量可恢复 |
IM 里的 Redis 用法
- 保存用户在线状态;
- 保存用户连接在哪台网关;
- 限制接口频率;
- 存验证码;
- 缓存用户资料;
- 做分布式锁;
- 用 Pub/Sub 或 Stream 做简单消息流。
4.6 消息队列
消息队列不是聊天消息本身,而是一种后端内部的异步通信工具。 比如用户发了一条消息,核心路径只做:
校验权限 -> 消息落库 -> 投递在线用户 -> 返回 ACK
其他事情可以丢到队列:
离线推送
内容审核
敏感词扫描
搜索索引
统计报表
AI 摘要
常见队列:
| 名称 | 粗略理解 |
|---|---|
| Kafka | 高吞吐日志型消息系统,大规模常见。 |
| RabbitMQ | 传统消息队列,路由能力强。 |
| NATS | 轻量、高性能消息系统。 |
| Redis Stream | Redis 里的流式队列能力。 |
4.7 Apollo 是什么
这里要区分两个常见的 Apollo。
| 名称 | 场景 | 含义 |
|---|---|---|
| Apollo 配置中心 | 国内后端常说的 Apollo | 携程开源的配置中心,用来动态管理服务配置。 |
| Apollo GraphQL | 前端/GraphQL 生态 | GraphQL 客户端和服务端工具链。 |
如果后端同事说「接 Apollo 配置」,大概率指 配置中心。
配置中心解决的问题是:不要把所有配置都写死在代码或 .env 里。
比如:
| 配置 | 为什么适合放配置中心 |
|---|---|
| Redis 地址 | 不同环境不一样。 |
| 数据库连接 | 开发、测试、生产不同。 |
| 是否开启注册 | 可以动态开关。 |
| 消息最大长度 | 可以不用发版就调整。 |
| AI 审核开关 | 模型异常时可以快速关闭。 |
前端类比:它像远程 .env + feature flag 管理后台。
5. IM 后端要额外关注什么
普通 CRUD 后端主要是「请求进来,查库,返回」。IM 后端多了实时性和连接状态。
5.1 消息 ID
每条消息都应该有唯一 ID。它用于:
- 去重;
- 排序;
- 客户端本地消息和服务端消息对齐;
- 断线重连后补拉。
5.2 消息顺序
用户关心聊天里的顺序。你需要考虑:
- 同一个会话里的消息如何排序;
- 服务端时间和客户端时间冲突怎么办;
- 多设备同时发送怎么办;
- 断线重连后如何补齐缺失消息。
5.3 ACK 和重试
客户端发送消息后,不能只靠 UI 判断成功。
常见状态:
本地创建 -> 发送中 -> 服务端已收到 -> 已投递 -> 已读
前端的“发送成功”最好对应后端 ACK。
5.4 在线和离线
在线用户可以通过 WebSocket 立即推送。离线用户要:
-
保存消息;
-
等用户上线后补拉;
-
可选发送系统推送;
-
避免重复推送。
5.5 多端同步
一个用户可能同时登录手机、平板、电脑。后端要考虑:
-
发给当前用户的其他设备;
-
已读状态同步;
-
撤回消息同步;
-
登录挤下线策略。
6. 推荐学习路线
第 1 阶段:后端基础
目标:能写最简单的 HTTP API。
-
Rust 基础语法;
-
Cargo;
-
Axum 路由;
-
JSON;
-
HTTP 状态码;
-
错误处理;
-
日志。
练习:
GET /v
POST /users/register
POST /users/login
GET /me
第 2 阶段:数据库
目标:数据能长期保存。
- PostgreSQL 或 MySQL;
- SQL;
- 表设计;
- 索引;
- 事务;
- 连接池;
- migration;
- Rust 里的 SQLx 或 SeaORM。
练习:
注册用户写入 users 表
登录时查询 users 表
创建 conversations 表
创建 messages 表
第 3 阶段:鉴权
目标:后端知道用户是谁。
-
密码哈希;
-
JWT 或 Session;
-
Middleware;
-
权限校验;
-
Token 过期和刷新。
练习:
只有登录用户才能创建会话
只有会话成员才能发送消息
第 4 阶段:WebSocket
目标:能实时收发消息。
-
WebSocket 连接建立;
-
心跳;
-
断线重连;
-
消息 ACK;
-
用户连接管理;
-
Tokio 任务和 channel。
练习:
客户端 A 发消息
服务端通过 WebSocket 推给客户端 B
客户端 B 返回 ACK
第 5 阶段:Redis
目标:管理临时状态和高频数据。
-
Key-Value;
-
过期时间;
-
Hash;
-
Set;
-
限流;
-
在线状态;
-
分布式锁基础。
练习:
用户上线时写入 online:user_id
断线或心跳超时后删除在线状态
验证码 5 分钟过期
第 6 阶段:队列和异步任务
目标:把非核心流程从发消息主链路拆出去。
- MQ 基础;
- 生产者/消费者;
- 重试;
- 死信队列;
- 幂等处理。
练习:
消息落库后发出 MessageCreated 事件
Worker 消费事件并做离线推送
第 7 阶段:配置、部署和观测
目标:服务能在真实环境运行和排查。
- 环境变量;
- 配置中心 Apollo;
- Docker;
- Linux;
- 日志;
- metrics;
- tracing;
- 健康检查;
- 灰度发布。
7. Rust 后端技术栈建议
如果这个项目主要想用 Rust 做后端,可以从下面这套开始:
| 能力 | 推荐 |
|---|---|
| Web 框架 | Axum |
| 异步运行时 | Tokio |
| JSON 序列化 | serde / serde_json |
| 数据库 | PostgreSQL |
| 数据库访问 | SQLx 或 SeaORM |
| 缓存 | Redis |
| 日志 | tracing |
| 配置 | config / envy,后续接 Apollo |
| API 文档 | OpenAPI / utoipa |
| 部署 | Docker |
学习时不要一开始就把所有组件都接上。更稳的顺序是:
Axum HTTP -> PostgreSQL -> 登录鉴权 -> WebSocket -> Redis -> MQ -> Apollo/部署/监控
8. 最小 IM 后端 MVP 范围
第一版不要做太大。建议 MVP 只包含:
- 用户注册;
- 用户登录;
- 创建单聊会话;
- 发送文本消息;
- 查询历史消息;
- WebSocket 实时投递;
- 简单 ACK;
- 断线后重新拉历史消息。
暂时不要急着做:
- 大群;
- 端到端加密;
- 消息漫游复杂策略;
- 多机房;
- 复杂审核;
- AI 助手;
- 高级搜索;
- 精细已读回执。
这些都可以后续迭代。
9. 最重要的心智转换
前端入门后端,最容易卡在「我能不能写出接口」;但真正的后端思维是:
| 问题 | 后端要考虑 |
|---|---|
| 这个请求是谁发的? | 鉴权。 |
| 他有没有权限? | 权限模型。 |
| 数据是否可信? | 参数校验。 |
| 写库失败怎么办? | 错误处理和事务。 |
| 重复请求怎么办? | 幂等。 |
| 并发同时修改怎么办? | 锁、事务、版本号。 |
| 服务重启会不会丢数据? | 持久化。 |
| 用户断线怎么办? | 重连和补偿。 |
| 出问题怎么查? | 日志、trace、metrics。 |
一句话总结:
前端更关注「用户此刻看到什么」;后端更关注「系统最终承认什么事实,以及这个事实是否可靠」。
10. 建议你接下来怎么学
-
用 Axum 写 3 个 HTTP 接口:
/v、注册、登录。 -
接 PostgreSQL,把用户写进数据库。
-
加密码哈希和 JWT。
-
写一个 WebSocket echo 服务。
-
把 echo 改成单聊消息投递。
-
加 Redis 保存在线状态。
-
再考虑消息队列、Apollo、部署和监控。
学后端不要一开始追求架构完整。先让一条消息从 Flutter 发到 Rust,再从 Rust 推到另一个 Flutter 客户端;这条链路跑通后,数据库、Redis、队列、配置中心的意义会自然变清楚。