读懂 RinBlog:从函数到架构
本章目标
这一章把前面的知识放回当前项目。你会从请求流、数据模型、存储、HTML 渲染、文档站模块几个角度读懂 RinBlog,并理解它如何从教学项目演进成更清晰的工程。
它是什么
RinBlog 是一个极简 Rust Web 服务。它包含两条主线:
- 博客线:发布文章、保存到文件、查看文章。
- 教材线:读取
docs/Markdown、渲染 HTML、在线浏览。
这两条线共用 HTTP 服务器和响应结构,但业务数据来源不同。
为什么需要
学语法和读真实项目之间有落差。这个项目刻意小,让你能从入口读到每个函数;又足够完整,让你看到路由、解析、存储、渲染、安全边界。
工程架构的关键不是一开始就上复杂框架,而是能回答:
- 请求从哪里进来。
- 数据在哪里变形。
- 错误在哪里处理。
- 哪些模块知道哪些细节。
- 哪些输入必须被校验。
怎么使用
建议按这条路线读源码:
main:启动监听和创建文章目录。handle_connection:连接级处理。read_http_request:字节到请求结构体。route_inner:路径到功能。render_index_response和render_post_response:博客 HTML。docs::render_docs_response:教材 HTML。save_post、load_post:文件存储。escape_html:输出安全。
逐行解释
_ if request.method == "GET" && docs::is_docs_path(path) => docs::render_docs_response(path),
_表示前面的精确模式没有匹配时,进入这个带条件的分支判断。request.method == "GET"限定只有 GET 请求可以读文档。docs::is_docs_path(path)把文档路径判断交给 docs 模块。docs::render_docs_response(path)生成完整文档响应。- 这一行体现了模块边界:路由层只知道“交给 docs”,不知道 Markdown 如何读取和渲染。
常见坑
- 小项目也要有安全边界。
post_path校验数字 id,docs 模块使用章节白名单。 - HTML 输出用户内容必须转义。文章标题和正文都不能直接拼进 HTML。
- 教材 Markdown 是仓库可信内容,因此可以渲染为 HTML;用户提交的 Markdown 则需要更严格策略。
- 路由顺序会影响匹配结果,越具体的分支通常越靠前。
练习
- 画出一次
/docs请求经过的函数链。 - 画出一次
/postsPOST 请求经过的函数链。 - 找出哪些函数返回
io::Result,说明它们为什么可能失败。 - 找出所有把字符串拼成 HTML 的地方,确认是否需要转义。
造轮子任务
把路由解析单独抽象成 enum Route,再让 route_inner 先调用 parse_route(path)。这会让路由层从“字符串匹配”进化到“类型匹配”,也更适合后续扩展。
小结
RinBlog 的价值在于透明。它不完美,也不追求生产级能力,但它展示了一个 Web 服务的骨架。读懂它之后,再看 Axum、Actix Web、Rocket,你会更清楚框架在替你处理哪些层。