前后端交互
前后端交互的核心即是通过前后端交互接口,实现客户端与服务端之间交互。类似于一份客户端与服务端交互的协议
接口设计
客户端与服务器之间的通信协议
- 场景:服务器和客户端之间需要互相通信
- 策略:HTTP+WebSocket(应用层协议,主要实现服务器发送给客户端)
- 约定:
- HTTP:客户端发起的所有请求统一按照POST
- 服务器传递数据方法:通过body传输给服务器,使用不同路径区分不同的功能
- 统一使用protobuffer序列化反序列化:HTTP请求、HTTP响应、body部分
核心Protobuf设计
基础base.proto设计思路
- 通信使用的数据结构:用户信息、聊天回话、消息类型和传输结构
- 不同的消息类型,设计成不同的结构体,每个结构体中封装对应数据
- 针对于某些不是每次都必须的消息类型,将其设计成optional字段进行处理
- enum和oneof来区分不同类型的消息,MessageType采用枚举方式来定义四种消息类型,同时MessageContent使用oneof将这些不同的消息组合在一起
syntax = "proto3";
package bite_im;
option cc_generic_services = true;
// 用户信息结构
message UserInfo {
string user_id = 1; // 用户ID
string nickname = 2; // 昵称
string description = 3; // 个性签名
string phone = 4; // 手机号
bytes avatar = 5; // 头像(二进制数据)
}
// 聊天会话信息
message ChatSessionInfo {
optional string single_chat_friend_id = 1; // 单聊时设置为对方ID
string chat_session_id = 2; // 会话ID
string chat_session_name = 3; // 会话名称
optional MessageInfo prev_message = 4; // 上一条消息
optional bytes avatar = 5; // 单聊时为对方头像
}
// 消息类型枚举
enum MessageType {
STRING = 0; // 文字消息
IMAGE = 1; // 图片消息
FILE = 2; // 文件消息
SPEECH = 3; // 语音消息
}
// 文字消息结构
message StringMessageInfo {
string content = 1; // 文本内容
}
// 图片消息结构
message ImageMessageInfo {
optional string file_id = 1; // 图片文件ID
optional bytes image_content = 2; // 图片二进制数据
}
// 文件消息结构
message FileMessageInfo {
optional string file_id = 1; // 文件ID
int64 file_size = 2; // 文件大小
string file_name = 3; // 文件名称
optional bytes file_contents = 4; // 文件二进制数据
}
// 语音消息结构
message SpeechMessageInfo {
optional string file_id = 1; // 语音文件ID
optional bytes file_contents = 2; // 语音二进制数据
}
// 消息内容
message MessageContent {
MessageType message_type = 1; // 消息类型
oneof msg_content {
StringMessageInfo string_message = 2; // 文字消息
FileMessageInfo file_message = 3; // 文件消息
SpeechMessageInfo speech_message = 4; // 语音消息
ImageMessageInfo image_message = 5; // 图片消息
}
}
// 消息信息结构
message MessageInfo {
string message_id = 1; // 消息ID
string chat_session_id = 2; // 会话ID
int64 timestamp = 3; // 时间戳
UserInfo sender = 4; // 发送者信息
MessageContent message = 5; // 消息内容
}
// 消息封装
message Message {
string request_id = 1; // 请求ID
MessageInfo message = 2; // 消息信息
}
// 文件下载数据
message FileDownloadData {
string file_id = 1; // 文件ID
bytes file_content = 2; // 文件二进制内容
}
// 文件上传数据
message FileUploadData {
string file_name = 1; // 文件名称
int64 file_size = 2; // 文件大小
bytes file_content = 3; // 文件二进制内容
}
单个文件和多个文件上传于下载
- 文件请求与响应消息的设计
- 对于文件获取和上传操作的设计
/*
文件操作服务的子服务注册信息:/service/file/instance_id
服务名称:/service/file
实例ID:instance_id,代表每个子服务器的唯一ID,能够提供文件操作服务
服务发现时通过 /service/file 获取所有能够提供文件操作的实例信息
*/
syntax = "proto3";
package bite_im;
import "base.proto";
option cc_generic_services = true;
// 获取单个文件的请求
message GetSingleFileReq {
string request_id = 1; // 请求ID
string file_id = 2; // 文件ID
optional string user_id = 3; // 用户ID(可选)
optional string session_id = 4; // 会话ID(可选)
}
// 获取单个文件的响应
message GetSingleFileRsp {
string request_id = 1; // 请求ID
bool success = 2; // 操作是否成功
string errmsg = 3; // 错误信息
FileDownloadData file_data = 4; // 文件下载数据
}
// 获取多个文件的请求
message GetMultiFileReq {
string request_id = 1; // 请求ID
optional string user_id = 2; // 用户ID(可选)
optional string session_id = 3; // 会话ID(可选)
repeated string file_id_list = 4; // 文件ID列表
}
// 获取多个文件的响应
message GetMultiFileRsp {
string request_id = 1; // 请求ID
bool success = 2; // 操作是否成功
string errmsg = 3; // 错误信息
repeated FileDownloadData file_data = 4; // 文件下载数据列表
}
// 上传单个文件的请求
message PutSingleFileReq {
string request_id = 1; // 请求ID
optional string user_id = 2; // 用户ID(可选)
optional string session_id = 3; // 会话ID(可选)
FileUploadData file_data = 4; // 文件上传数据
}
// 上传单个文件的响应
message PutSingleFileRsp {
string request_id = 1; // 请求ID
bool success = 2; // 操作是否成功
string errmsg = 3; // 错误信息
FileMessageInfo file_info = 4; // 文件信息
}
// 上传多个文件的请求
message PutMultiFileReq {
string request_id = 1; // 请求ID
optional string user_id = 2; // 用户ID(可选)
optional string session_id = 3; // 会话ID(可选)
repeated FileUploadData file_data = 4; // 文件上传数据列表
}
// 上传多个文件的响应
message PutMultiFileRsp {
string request_id = 1; // 请求ID
bool success = 2; // 操作是否成功
string errmsg = 3; // 错误信息
repeated FileMessageInfo file_info = 4; // 文件信息列表
}
// 文件操作服务接口定义
service FileService {
// 获取单个文件
rpc GetSingleFile(GetSingleFileReq) returns (GetSingleFileRsp);
// 获取多个文件
rpc GetMultiFile(GetMultiFileReq) returns (GetMultiFileRsp);
// 上传单个文件
rpc PutSingleFile(PutSingleFileReq) returns (PutSingleFileRsp);
// 上传多个文件
rpc PutMultiFile(PutMultiFileReq) returns (PutMultiFileRsp);
}
protobuf在项目中使用
修改CMAKE文件
核心数据结构转换
用户信息的Protobuf转换逻辑
消息类型的Protobuf逻辑实现
会话消息Protobuf转换逻辑
数据中心类
数据中心类设计成单例模式
核心数据类型设计
持久化存储的实现
- 登录会话ID
- 存储未读消息内容
初始化存储数据的文件夹
保存数据内存
数据加载到内存中逻辑的实现