
🎬 个人主页 :艾莉丝努力练剑
❄专栏传送门 :《C语言》《数据结构与算法》《C/C++干货分享&学习过程记录》
《Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享》
⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平
🎬 艾莉丝的简介:

文章目录
- [1 ~> ChatServer HTTP接口模块实现总览](#1 ~> ChatServer HTTP接口模块实现总览)
-
- [1.1 整体类结构(ChatServer.h头文件)](#1.1 整体类结构(ChatServer.h头文件))
-
- [1.1.1 类成员与访问权限](#1.1.1 类成员与访问权限)
- [1.1.2 必须引入的头文件](#1.1.2 必须引入的头文件)
- [1.2 公共工具函数实现 buildResponse](#1.2 公共工具函数实现 buildResponse)
- [2 ~> 各个HTTP接口业务实现](#2 ~> 各个HTTP接口业务实现)
-
- [2.1 创建会话接口 handleCreateSessionRequest](#2.1 创建会话接口 handleCreateSessionRequest)
- [2.2 获取会话列表 handleGetSessionListsRequest](#2.2 获取会话列表 handleGetSessionListsRequest)
- [2.3 获取模型列表 handleGetModelListRequest](#2.3 获取模型列表 handleGetModelListRequest)
- [2.4 删除会话 handleDeleteSessionRequest](#2.4 删除会话 handleDeleteSessionRequest)
- [2.5 获取会话历史消息 handleGetHistoryMessagesRequest](#2.5 获取会话历史消息 handleGetHistoryMessagesRequest)
- [2.6 发送消息‑全量返回 handleSendMessageRequest](#2.6 发送消息‑全量返回 handleSendMessageRequest)
- [3 ~> SSE流式增量返回接口(核心难点)](#3 ~> SSE流式增量返回接口(核心难点))
-
- [3.1 SSE协议基础概念](#3.1 SSE协议基础概念)
- [3.2 sendMessageStreamRequest 流式发送消息实现](#3.2 sendMessageStreamRequest 流式发送消息实现)
- [4 ~> 关键易错点汇总(面试/考试重点)](#4 ~> 关键易错点汇总(面试/考试重点))
-
- [4.1 Jsoncpp库易错](#4.1 Jsoncpp库易错)
- [4.2 httplib库易错](#4.2 httplib库易错)
- [4.3 业务接口错误码规范](#4.3 业务接口错误码规范)
- [4.4 代码复用优化思想](#4.4 代码复用优化思想)
- [4.5 全量返回 vs SSE增量返回对比](#4.5 全量返回 vs SSE增量返回对比)
- [4.6 SDK回调层原理补充](#4.6 SDK回调层原理补充)
- 结尾

1 ~> ChatServer HTTP接口模块实现总览
基于httplib实现HTTP服务,封装AI聊天业务接口;分为头文件类声明、接口业务实现、公共工具函数、SSE流式增量返回四大模块;接口遵循REST风格,统一JSON报文格式,区分路径参数、Body请求参数;包含错误码、异常处理、代码复用抽象。
1.1 整体类结构(ChatServer.h头文件)
1.1.1 类成员与访问权限
- public 对外接口
- 构造:
ChatServer(const ServerConfig& config); - 析构:
~ChatServer(); bool start();启动http服务void stop();停止http服务bool isRunning() const;查询服务运行状态
- 构造:
- private 私有成员方法:HTTP请求处理器
- 公共工具:
std::string buildResponse(const std::string& message, bool success = false);统一构造JSON响应字符串 void handleCreateSessionRequest(const httplib::Request& request, httplib::Response& response);创建会话 POST/api/sessionvoid handleGetSessionListsRequest(const httplib::Request& request, httplib::Response& response);获取会话列表 GET/api/sessionsvoid handleGetModelListRequest(const httplib::Request& request, httplib::Response& response);获取模型列表 GET/api/modelsvoid handleDeleteSessionRequest(const httplib::Request& request, httplib::Response& response);删除会话 DELETE/api/session/{session_id}void handleGetHistoryMessagesRequest(const httplib::Request& request, httplib::Response& response);获取历史消息 GET/api/session/{session_id}/historyvoid handleSendMessageRequest(const httplib::Request& request, httplib::Response& response);发送消息全量返回 POST/api/messagevoid handleSendMessageStreamRequest(const httplib::Request& request, httplib::Response& response);发送消息SSE增量流式返回 POST/api/message/async
- 公共工具:
- private 私有成员变量
ServerConfig _config;服务器配置std::unique_ptr<httplib::Server> _chatServer{nullptr};httplib http服务实例std::shared_ptr<ai_chat_sdk::ChatSDK> _chatSDK{nullptr};AI聊天SDK实例,完成底层模型交互std::atomic<bool> _isRunning{false};原子布尔标记服务运行状态
1.1.2 必须引入的头文件
cpp
#include "ChatServer.h"
#include <ai_chat_sdk/util/myLog.h>
#include <jsoncpp/json/forwards.h>
#include <jsoncpp/json/value.h>
#include <jsoncpp/json/reader.h>
1.2 公共工具函数实现 buildResponse
消除重复JSON序列化代码,统一构造success/message基础响应报文;返回序列化后的JSON字符串。
cpp
// ChatServer.cpp
namespace ai_chat_server {
std::string ChatServer::buildResponse(const std::string& message, bool success)
{
Json::Value responseJson;
responseJson["success"] = success;
responseJson["message"] = message;
Json::StreamWriterBuilder writerBuilder;
return Json::writeString(writerBuilder, responseJson);
}
}
2 ~> 各个HTTP接口业务实现
2.1 创建会话接口 handleCreateSessionRequest
- 请求信息
- URL:
POST /api/session - 参数:http body JSON,
modelstring 模型名称 - 返回200;参数解析错误返回400;内部创建会话失败返回500
- 返回JSON结构
{ "success": true, "message": "create session success", "data": { "session_id": "string", "model": "string" } }
- URL:
- 业务执行流程
- 获取request.body,使用
Json::Reader反序列化请求体JSON;解析失败调用buildResponse返回错误,设置status=400。 - 从json对象读取
model字段,设置默认模型。 - 调用
_chatSDK->createSession(modelName)生成session_id;session_id为空代表内部错误,status=500返回错误。 - 组装成功响应data对象,填充session_id、model;序列化json,status=200设置响应content-type为
application/json。
- 获取request.body,使用
cpp
void ChatServer::handleCreateSessionRequest(const httplib::Request& request, httplib::Response& response)
{
// 1.反序列化请求body
Json::Value requestJson;
Json::Reader reader;
if (!reader.parse(request.body, requestJson))
{
std::string errStr = buildResponse("parse request body failed,json format error", false);
response.status = 400;
response.set_content(errStr, "application/json");
return;
}
//2.读取model参数,设置默认值
std::string modelName = requestJson.get("model", "deepseek‑chat").asString();
//3.调用SDK创建会话
std::string sessionID = _chatSDK->createSession(modelName);
if (sessionID.empty())
{
std::string errStr = buildResponse("create session failed", false);
response.status = 500;
response.set_content(errStr, "application/json");
return;
}
//4.组装成功返回报文
Json::Value dataJson;
dataJson["session_id"] = sessionID;
dataJson["model"] = modelName;
Json::Value respJson;
respJson["success"] = true;
respJson["message"] = "create session success";
respJson["data"] = dataJson;
Json::StreamWriterBuilder writerBuilder;
std::string respStr = Json::writeString(writerBuilder, respJson);
response.status = 200;
response.set_content(respStr, "application/json");
}
2.2 获取会话列表 handleGetSessionListsRequest
- 请求信息
- URL:
GET /api/sessions,无body参数 - 返回200;data是会话对象数组
- URL:
json
{
"success":true,
"message":"get session lists success",
"data":[
{
"id":"string",
"model":"string",
"created_at":1730000000,
"updated_at":1730000100,
"message_count":2,
"first_user_message":"第一条用户消息内容"
}
]
}
- 业务流程
- 调用SDK获取全部sessionId列表。
- 创建Json数组
Json::Value dataArray(Json::arrayValue); - 遍历每个sessionId,
_chatSDK->getSession(sessionID)拿到会话智能指针;会话非空组装json对象。 - 时间戳使用
static_cast<int64_t>强转;消息非空取_messages.front()->_content第一条消息。 - append到数组;组装外层responseJson,序列化返回。
cpp
void ChatServer::handleGetSessionListsRequest(const httplib::Request& request, httplib::Response& response)
{
std::vector<std::string> sessionIDs = _chatSDK->getSessionLists();
Json::Value dataArray(Json::arrayValue);
for(const auto& sessionID : sessionIDs)
{
auto session = _chatSDK->getSession(sessionID);
if(!session) continue;
Json::Value itemJson;
itemJson["id"] = session->_sessionId;
itemJson["model"] = session->_modelName;
itemJson["created_at"] = static_cast<int64_t>(session->_createdAt);
itemJson["updated_at"] = static_cast<int64_t>(session->_updatedAt);
itemJson["message_count"] = static_cast<int>(session->_messages.size());
if(!session->_messages.empty())
{
itemJson["first_user_message"] = session->_messages.front()._content;
}
dataArray.append(itemJson);
}
Json::Value respJson;
respJson["success"] = true;
respJson["message"] = "get session lists success";
respJson["data"] = dataArray;
Json::StreamWriterBuilder wb;
std::string respStr = Json::writeString(wb, respJson);
response.status = 200;
response.set_content(respStr, "application/json");
}
2.3 获取模型列表 handleGetModelListRequest
- 请求信息
- URL:
GET /api/models,无参数 - 返回data数组,每一项包含
name模型名,desc模型描述
- URL:
json
{
"success":true,
"message":"get model lists success",
"data":[
{"name":"deepseek‑chat","desc":"xxx描述"}
]
}
void ChatServer::handleGetModelListRequest(const httplib::Request& request, httplib::Response& response)
{
auto modelList = _chatSDK->getAvailableModels();
Json::Value dataArray(Json::arrayValue);
for(const auto& info : modelList)
{
Json::Value item;
item["name"] = info._modelName;
item["desc"] = info._modelDesc;
dataArray.append(item);
}
Json::Value respJson;
respJson["success"] = true;
respJson["message"] = "get model lists success";
respJson["data"] = dataArray;
Json::StreamWriterBuilder wb;
std::string respStr = Json::writeString(wb, respJson);
response.status = 200;
response.set_content(respStr, "application/json");
}
2.4 删除会话 handleDeleteSessionRequest
- 请求信息
- URL:
DELETE /api/session/{session_id},路径参数 - httplib路径匹配捕获的参数保存在
request.matches;matches1取session_id - 删除成功返回200;会话不存在返回404
- URL:
json
{
"success":true,
"message":"delete session success"
}
void ChatServer::handleDeleteSessionRequest(const httplib::Request& request, httplib::Response& response)
{
std::string sessionId = request.matches[1];
bool ok = _chatSDK->deleteSession(sessionId);
if(ok)
{
std::string respStr = buildResponse("delete session success", true);
response.status = 200;
response.set_content(respStr, "application/json");
}
else
{
std::string respStr = buildResponse("delete session failed,session not found", false);
response.status = 404;
response.set_content(respStr, "application/json");
}
}
2.5 获取会话历史消息 handleGetHistoryMessagesRequest
- 请求信息
- URL:
GET /api/session/{session_id}/history,路径参数session_id - 会话不存在返回404;成功返回200,data数组存储消息
- URL:
json
{
"success":true,
"message":"get history messages success",
"data":[
{
"id":"msg‑id",
"role":"user/assistant",
"content":"消息文本",
"timestamp":1730000000
}
]
}
void ChatServer::handleGetHistoryMessagesRequest(const httplib::Request& request, httplib::Response& response)
{
std::string sessionId = request.matches[1];
auto session = _chatSDK->getSession(sessionId);
if(!session)
{
std::string err = buildResponse("session not found", false);
response.status = 404;
response.set_content(err, "application/json");
return;
}
Json::Value dataArray(Json::arrayValue);
for(const auto& msg : session->_messages)
{
Json::Value item;
item["id"] = msg._messageId;
item["role"] = msg._role;
item["content"] = msg._content;
item["timestamp"] = static_cast<int64_t>(msg._timestamp);
dataArray.append(item);
}
Json::Value respJson;
respJson["success"] = true;
respJson["message"] = "get history messages success";
respJson["data"] = dataArray;
Json::StreamWriterBuilder wb;
std::string respStr = Json::writeString(wb, respJson);
response.status = 200;
response.set_content(respStr, "application/json");
}
2.6 发送消息‑全量返回 handleSendMessageRequest
- 请求信息
- URL:
POST /api/message - Body JSON参数:
session_id会话id,message用户输入消息 - 返回200;参数解析失败400;调用模型失败500
- URL:
json
{
"success":true,
"message":"send message success",
"data":{
"session_id":"xxx",
"response":"模型完整回答文本"
}
}
void ChatServer::handleSendMessageRequest(const httplib::Request& request, httplib::Response& response)
{
Json::Value reqJson;
Json::Reader reader;
if(!reader.parse(request.body, reqJson))
{
std::string err = buildResponse("parse request body failed,json format error", false);
response.status = 400;
response.set_content(err, "application/json");
return;
}
std::string sessionId = reqJson["session_id"].asString();
std::string message = reqJson["message"].asString();
if(sessionId.empty() || message.empty())
{
std::string err = buildResponse("session_id or message is empty", false);
response.status = 400;
response.set_content(err, "application/json");
return;
}
std::string assistantMsg = _chatSDK->sendMessage(sessionId, message);
if(assistantMsg.empty())
{
std::string err = buildResponse("Failed to send AI response message", false);
response.status = 500;
response.set_content(err, "application/json");
return;
}
Json::Value dataJson;
dataJson["session_id"] = sessionId;
dataJson["response"] = assistantMsg;
Json::Value respJson;
respJson["success"] = true;
respJson["message"] = "send message success";
respJson["data"] = dataJson;
Json::StreamWriterBuilder wb;
std::string respStr = Json::writeString(wb, respJson);
response.status = 200;
response.set_content(respStr, "application/json");
}
3 ~> SSE流式增量返回接口(核心难点)
3.1 SSE协议基础概念
- SSE(Server‑Sent Events):http长连接,服务器单向持续向客户端推送数据;不需要WebSocket。
- 报文格式规范
- 每一条推送:
data: 内容\n\n;必须两个换行符作为分隔。 - 流结束标记:
data: [DONE]\n\n
- 每一条推送:
- http响应头配置
Cache‑Control: no‑cache:禁用缓存,实时下发Connection: keep‑alive:维持长连接- 使用httplib
set_chunked_content_provider开启分块传输;回调参数DataSink用于直接写入网络输出流。
- 回调函数签名:
bool(size_t offset, httplib::DataSink& sink)- 返回
true代表还有后续数据;false终止流。 DataSink.write(buf, len)写入字节流;DataSink.done()结束流式输出。
- 返回
- 注意:chunk内容必须做json转义,防止内容内换行、引号破坏SSE协议格式,使用
Json::valueToQuotedString。
3.2 sendMessageStreamRequest 流式发送消息实现
- 请求信息
- URL:
POST /api/message/async - Body参数:
session_id,message用户消息 - HTTP状态码固定200;响应Content‑Type不是普通json,使用SSE分块输出
- URL:
- SDK回调说明:
_chatSDK->sendMessageStream(sessionId, msg, callback(chunk, last))- chunk:模型返回的增量文本片段
- last:bool,true代表整个流式输出结束
cpp
void ChatServer::handleSendMessageStreamRequest(const httplib::Request& request, httplib::Response& response)
{
// 1.解析请求体
Json::Value reqJson;
Json::Reader reader;
if(!reader.parse(request.body, reqJson))
{
std::string err = buildResponse("parse request body failed,json format error", false);
response.status = 400;
response.set_content(err, "application/json");
return;
}
std::string sessionId = reqJson["session_id"].asString();
std::string message = reqJson["message"].asString();
if(sessionId.empty() || message.empty())
{
std::string err = buildResponse("session_id or message is empty", false);
response.status = 400;
response.set_content(err, "application/json");
return;
}
// 2.配置SSE响应头
response.status = 200;
response.set_header("Cache‑Control", "no‑cache");
response.set_header("Connection", "keep‑alive");
// 3.开启分块传输回调
response.set_chunked_content_provider("text/event‑stream",
[this, sessionId, message](size_t offset, httplib::DataSink& sink) -> bool
{
// SDK的chunk回调,把模型分片转为SSE报文写入DataSink
auto writeChunk = [&sink](const std::string& chunk, bool last)
{
// json转义,避免特殊字符破坏SSE协议
std::string escaped = Json::valueToQuotedString(chunk.c_str());
std::string sseFrame = "data:" + escaped + "\n\n";
sink.write(sseFrame.data(), sseFrame.size());
if(last)
{
std::string doneFrame = "data:[DONE]\n\n";
sink.write(doneFrame.data(), doneFrame.size());
sink.done();
}
};
// 先发空帧,防止客户端长时间阻塞等待
writeChunk("", false);
// 调用SDK流式接口,传入分片回调
_chatSDK->sendMessageStream(sessionId, message, writeChunk);
return true;
}
);
}
4 ~> 关键易错点汇总(面试/考试重点)
4.1 Jsoncpp库易错
Json::Reader::parse():传入request.body字符串,输出到外部Json::Value&;解析失败返回false,必须返回400错误。Json::StreamWriterBuilder用于序列化C++对象到json字符串。Json::valueToQuotedString:字符串转义,SSE场景必须使用,否则内容的"、\n会破坏协议帧。- 创建json数组必须显式:
Json::Value arr(Json::arrayValue);,否则默认是object对象。
4.2 httplib库易错
- 路径参数获取 :DELETE/get历史消息接口,路径捕获值存放在
request.matches数组,下标从1开始。 set_chunked_content_provider- content‑type SSE标准是
text/event‑stream,不能写application/json。 - 回调函数捕获变量注意生命周期;lambda捕获
this访问类成员。 - DataSink.write直接写原始字节;不要使用response.set_content,流式场景无效。
- sink.done()标记流结束。返回true表示还存在后续数据。
- content‑type SSE标准是
- response.status修改状态码,
set_content(字符串, content‑type)设置普通http body。
4.3 业务接口错误码规范
| http状态码 | 业务含义 |
|---|---|
| 200 | 请求业务处理成功(不管是普通json还是sse流) |
| 400 | 请求体JSON解析失败 / 请求参数为空、非法 |
| 404 | session_id不存在,找不到会话资源 |
| 500 | 服务器内部业务错误:创建会话失败、调用大模型返回空 |
4.4 代码复用优化思想
- 原始代码每个接口重复编写
errorJson + StreamWriterBuilder序列化逻辑。 - 抽离
buildResponse(message, success)公共工具函数,统一生成success/message结构JSON字符串,消除大量重复样板代码。 - 创建会话、删除会话、历史消息全部复用该工具。
4.5 全量返回 vs SSE增量返回对比
| 维度 | 全量返回 sendMessage | SSE增量返回 sendMessageStream |
|---|---|---|
| 返回时机 | 等待模型完整全部回答完成一次性返回 | 模型每产生一段分片,立刻推送客户端 |
| http模式 | 普通一次性响应 | chunked分块长连接,SSE协议 |
| 适用场景 | 后端脚本、服务间调用 | web前端聊天页面,打字机实时输出效果 |
| 结束标识 | http连接正常关闭 | 服务主动下发data:[DONE]\n\n帧 |
4.6 SDK回调层原理补充
sendMessageStream内部是异步事件回调:
- SDK底层发起http请求访问大模型服务。
- 收到SSE分片数据,解析chunk。
- 执行上层传入回调函数,将分片交付ChatServer层。
- ChatServer层将分片封装SSE帧,写入httplib的DataSink推送给浏览器客户端。
- 模型流结束时,回调参数
last=true,服务发送[DONE]帧调用sink.done()关闭客户端长连接。
注意: 需要先发空分片给客户端,解决客户端请求发出之后,模型思考时间较长导致浏览器假死无响应的交互问题。
结尾
uu们,本文的内容到这里就全部结束了,艾莉丝在这里再次感谢您的阅读!
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ### 艾莉丝努力练剑 C/C++ & Linux 底层探索者 | 一个正在努力练剑的技术博主 *** ** * ** *** 👀 【关注】 跟随我一起深耕技术领域,见证每一次成长。 ❤️ 【点赞】 让优质内容被更多人看见,让知识传递更有力量。 ⭐ 【收藏】 把核心知识点存好,在需要时随时查、随时用。 💬 【评论】 分享你的经验或疑问,评论区一起交流避坑! 不要忘记给博主"一键四连"哦! "今日练剑达成!"
"技术之路难免有困惑,但同行的人会让前进更有方向。" |
结语:希望对学习Linux相关内容的uu有所帮助,不要忘记给博主"一键四连"哦!
往期回顾:
🗡博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧!🗡 ૮₍ ˶ ˊ ᴥ ˋ˶₎ა
