本文档用于定义一个基于 Jupyter Notebook (.ipynb) 交付的 HTTP Server 项目规划。项目目标是在尽量不依赖高级框架和现成服务封装的前提下,使用 Python 基础能力构建一个可运行、可观察、可扩展的最小 HTTP 服务系统,并以 Notebook 作为唯一核心实现载体。
本文档将覆盖:
- 项目目标与边界
- 交付形式与技术原则
- 功能需求与非功能需求
- Notebook 内部结构设计
- 核心模块拆解
- 分阶段实施路径
- 验收标准
- 风险与约束
- 后续扩展规划
- 项目发起人
- 项目实现者
- 后续维护者
- 需要基于该项目继续扩展功能的开发者
本 PRD 只定义:
- 一个详细的项目规划书
md - 一个后续将被实现为
ipynb的项目结构与功能规范
本 PRD 不直接包含:
- 最终代码实现
- 最终
.ipynb文件内容 - 自动化部署方案
- 生产级运维方案
基于 Jupyter Notebook 的 From-Scratch HTTP Server
构建一个完全基于 Jupyter Notebook 展开的 HTTP Server 项目,使其具备以下特征:
- 使用 Python 低层能力完成 HTTP 服务的核心链路
- 不依赖 Flask、FastAPI、Django、aiohttp、Tornado 等高级 Web 框架
- 不直接调用现成的高层 HTTP Server 封装作为核心实现
- 在 Notebook 中逐步构建 socket 监听、请求解析、响应生成、路由分发和静态文件返回能力
- 形成一套结构清晰、可运行、可验证的基础服务实现
该项目定位为一个“从基础协议与网络连接出发实现 HTTP 服务”的 Notebook 化项目资产,强调:
- 原理清晰
- 代码路径透明
- 模块边界明确
- 可以逐步演进
- 每个部分都能单独运行、观察和验证
项目完成后应提供以下价值:
- 提供一个从底层搭建 HTTP Server 的完整实现蓝图
- 让后续扩展具备稳定基础,例如增加路由、文件服务、状态码处理、请求头处理等
- 为后续继续拆解协议细节、错误分支、性能限制提供明确骨架
- 通过 Notebook 形式保留完整的实现过程与验证结果
绝大多数 Python Web 项目都会直接建立在成熟框架之上,这使得 HTTP 服务的底层结构被大量封装,开发效率很高,但不利于从协议与网络层角度建立清晰的系统认知。对于一个以“从零构建”为核心约束的项目,直接使用高级框架会削弱项目目标。
同时,如果完全使用普通 .py 组织实现,虽然更接近工程化代码形态,但不利于在开发初期逐段观察 socket 行为、报文内容、解析过程和中间状态。Notebook 在这个场景下更适合作为阶段性交付形式,因为它可以:
- 按单元分段执行
- 展示中间变量和原始字节内容
- 便于记录请求样例与测试结果
- 便于逐步演进
当前项目目录为空,尚未存在任何实现文件、设计文档或 Notebook。适合直接按统一规划建立项目结构,不存在兼容旧代码的问题。
本项目将以 Notebook 为唯一核心交付物展开,优先完成单文件、单进程、基础阻塞式 HTTP Server 的实现,再为后续增强能力预留扩展接口。
本期规划的实现范围包括:
- 在
ipynb中建立 HTTP Server 的完整实现过程 - 基于
socket构建 TCP 监听服务 - 接收客户端连接并读取原始请求数据
- 解析 HTTP Request Line
- 解析基础请求头
- 提取方法、路径、协议版本
- 构建基础路由分发机制
- 返回标准 HTTP Response
- 支持文本响应
- 支持简单 HTML 响应
- 支持读取本地静态文件并返回内容
- 支持基础错误响应,如
404 Not Found、400 Bad Request - 支持最基本的日志输出
- 提供 Notebook 内的运行说明、验证方式和结果示例
以下内容明确不纳入本期实现范围:
- 不引入 Flask / FastAPI / Django / aiohttp / Tornado
- 不使用 gunicorn / uvicorn / waitress 作为核心运行器
- 不实现多进程或多线程并发模型
- 不实现异步 IO 架构
- 不实现 HTTPS / TLS
- 不实现复杂模板引擎
- 不实现数据库集成
- 不实现 Session / Cookie 管理体系
- 不实现生产级静态资源缓存机制
- 不实现反向代理或负载均衡
- 不实现完整 RFC 级别 HTTP 协议覆盖
- 不追求生产环境性能指标
“from scratch” 在本项目中的具体含义如下:
- 从 TCP socket 建立服务入口
- 自行处理连接、读取、解析和响应流程
- 自行拼接 HTTP 响应报文
- 自行处理最基础的路由逻辑
- 自行读取文件并生成合适的响应头与响应体
- 优先使用 Python 标准库
为保证项目目标清晰,以下方式应避免作为核心实现:
- 使用现成框架注册路由
- 使用
http.server直接完成整个服务的核心功能 - 使用高级封装隐藏请求解析过程
- 使用自动响应对象抽象掉原始 HTTP 报文结构
说明:
允许参考标准库中某些低层模块辅助实现,例如:
socketpathlibosmimetypesdatetimeurllib.parse
但这些模块只能作为基础工具,不能替代核心 HTTP 服务逻辑本身。
项目的主实现必须放在 .ipynb 中,且 Notebook 不应只是演示代码片段,而应承担以下角色:
- 主实现容器
- 实验过程记录
- 结果验证载体
- 文档化执行流程
每个关键步骤都应具备可观察性,包括但不限于:
- 原始请求字节
- 解码后的请求文本
- 解析出的 method/path/version
- 路由匹配结果
- 返回的状态码
- 返回头部内容
- 文件读取路径
- 异常和错误分支
本项目后续的核心交付物应为:
- 一个主 Notebook 文件,例如:
http_server_from_scratch.ipynb
可选的辅助内容包括:
- 示例静态资源目录,例如
static/ - 示例 HTML 文件
- 示例文本文件
- README 或运行说明
但就本期规划而言,必须优先定义并完成的是 Notebook 本体设计。
Notebook 不是简单说明文档,而是“可执行的项目主体”。因此其内容需要同时满足:
- 可以从头按顺序执行
- 每段执行结果有意义
- 关键变量可输出
- 结构分层明确
- 最终能够运行出一个本地 HTTP 服务
用户希望通过运行 Notebook 中的若干代码单元,在本地启动一个最小 HTTP Server,并在浏览器中访问指定端口获得页面响应。
用户希望看到浏览器发来的原始请求内容,并能在 Notebook 中明确知道请求行、请求头和路径参数是如何被解析出来的。
用户希望在 Notebook 的路由映射结构中新增一个路径,例如 /about,并快速让服务返回新的文本或 HTML 内容。
用户希望通过 /static/... 形式请求本地文件,并由服务读取文件后返回内容,同时包含基本的 Content-Type。
用户希望访问不存在的路径时能够收到 404 响应,请求格式异常时收到 400 响应,从而验证服务具备最基本的鲁棒性。
本项目应至少包含以下功能模块:
- 服务配置模块
- Socket 监听模块
- 连接接收模块
- 请求读取模块
- 请求解析模块
- 路由分发模块
- 响应构建模块
- 静态文件处理模块
- 错误处理模块
- 日志输出模块
- Notebook 运行控制模块
以下章节将逐一拆解。
提供服务启动所需的基础参数配置。
HOSTPORTBUFFER_SIZEENCODINGSTATIC_DIRSERVER_NAMEDEFAULT_CONTENT_TYPE
- 配置值应集中出现在 Notebook 靠前位置
- 配置单元执行后可直接被后续所有单元复用
- 允许通过修改变量快速更换端口和静态目录
基于 socket 创建 TCP 服务端,完成:
- 创建 socket
- 绑定地址
- 进入监听状态
- 使用
AF_INET和SOCK_STREAM - 正确调用
bind() - 正确调用
listen() - 启动后打印监听地址
- 在 Notebook 中清晰展示服务进入监听状态
- 本期采用阻塞式实现
- 默认一次处理一个连接
- 不处理高并发优化
接收客户端连接,获取:
- 客户端 socket
- 客户端地址信息
- 调用
accept()接收连接 - 输出客户端 IP 和端口
- 对每次连接提供基本日志
- Notebook 环境中长时间阻塞会影响交互体验
- 需要在 PRD 中预留停止服务和中断单元的说明
从客户端连接中读取原始请求数据。
- 使用
recv()读取字节流 - 将原始字节保留为中间变量
- 提供字节到文本的解码流程
- 对空请求或异常读取情况有基础处理
应至少输出以下中间结果:
- 原始字节串
- 解码后的完整请求文本
- 请求文本按行拆分结果
将原始 HTTP 请求解析为结构化数据。
至少包括:
- HTTP 方法,例如
GET - 请求路径,例如
/ - 查询字符串,例如
?name=test - 协议版本,例如
HTTP/1.1 - 请求头键值对
- 正确拆分请求首行
- 能识别非法首行格式
- 请求头解析为字典结构
- 查询参数至少预留解析入口
建议在 Notebook 中将解析结果组织为类似结构:
request = {
"method": "GET",
"path": "/",
"query_string": "",
"http_version": "HTTP/1.1",
"headers": {},
"raw_text": "...",
}当出现以下情况时,应生成 400 Bad Request:
- 请求首行为空
- 首行字段数量不足
- 请求方法缺失
- 协议版本缺失
根据请求路径将请求转发到不同处理逻辑。
本期至少支持:
//hello/about/static/...
- 使用清晰可读的映射或条件分发方式
- 对未命中的路径返回
404 - 将静态资源路径与普通页面路径区分处理
- 路由逻辑应保持简单直观
- 避免过早抽象为复杂框架风格
- 处理函数与响应构建逻辑尽量分离
手动构建标准 HTTP 响应报文。
- Status Line
- Response Headers
- 空行分隔
- Response Body
- 能返回
200 OK - 能返回
404 Not Found - 能返回
400 Bad Request - 至少支持
Content-Type - 至少支持
Content-Length - 可选支持
Connection: close
- 响应头必须按 HTTP 文本格式拼接
- 响应体为字节时,应正确计算长度
- 字符串响应需统一编码
应明确区分:
- 响应头文本
- 响应体字节
- 最终发送给客户端的完整字节流
允许通过 URL 路径访问本地静态文件。
- 文本文件
- HTML 文件
- CSS 文件
- JavaScript 文件
- 常见图片文件类型可作为扩展项
- 从
/static/...中提取相对文件路径 - 拼接本地静态目录
- 判断文件是否存在
- 正确读取文件内容
- 根据扩展名推断
Content-Type
必须考虑基础路径安全,避免明显的目录穿越问题,例如:
../- 绝对路径逃逸
- 非法路径拼接
- 文件不存在返回
404 - 文件读取失败返回
500或本期约定错误响应
覆盖最关键的失败路径,保证服务在最小范围内可控。
- 非法请求格式
- 路径未命中
- 文件不存在
- 文件读取失败
- 编码异常
- socket 通信异常
- 错误必须有明确状态码
- 错误必须有可读响应体
- Notebook 中必须有日志输出,便于定位问题
提供最基本的运行日志,便于观察服务行为。
- 服务启动地址
- 收到连接的客户端地址
- 请求方法
- 请求路径
- 返回状态码
- 错误原因
- 优先简洁清晰
- 输出必须足够支持调试
- 不要求接入完整 logging 系统,可先使用基础打印
保证 Notebook 内的服务启动、停止、重复运行具备基本可控性。
- 明确哪个单元负责启动服务
- 明确服务启动后将持续阻塞
- 提供停止方式说明
- 说明重复运行前可能需要先中断旧实例
Notebook 与常规脚本不同,服务运行单元可能长期占用执行状态,因此必须在文档中明确操作顺序和中断方式。
Notebook 中的代码必须具备较高可读性:
- 变量名清晰
- 单元边界明确
- 每一段实现有明确职责
- 必要时有简短注释
从头顺序执行 Notebook 时,应能够在合理环境下成功启动服务并完成基础访问验证。
关键实现步骤应尽量展开,而不是过度封装为黑盒函数。即使后续会抽函数,也应保留足够可见的处理链路。
虽然项目本期只实现基础能力,但结构上应能支持后续增加:
- 更多路由
- 更多状态码
- 更完整的请求头解析
- POST 请求处理
- 更丰富的静态文件能力
本期不要求生产级稳定性,但至少应满足:
- 常规
GET请求可正常处理 - 非法请求不导致整个 Notebook 逻辑失控
- 不存在明显的路径拼接安全漏洞
推荐技术边界如下:
- 语言:Python
- 交付:Jupyter Notebook (
.ipynb) - 核心网络:
socket - 路径处理:
pathlib或os.path - MIME 推断:
mimetypes - 查询参数辅助解析:
urllib.parse
- Flask
- FastAPI
- Django
- aiohttp
- Tornado
- Bottle
- Sanic
- uvicorn
- gunicorn
本项目原则上不应以 http.server 为核心方案,因为这会明显削弱“from scratch”的目标。若后续作为对照参考,可以单独说明,但不能作为主实现路径。
Notebook 应按“先定义,再验证,最后运行”的逻辑组织,而不是随意堆叠代码单元。
建议最终 Notebook 至少包含以下章节:
- 项目说明
- 依赖与约束说明
- 全局配置
- HTTP 基础格式说明
- 创建 socket 服务
- 接收并打印原始请求
- 解析请求行与请求头
- 构建响应函数
- 构建路由函数
- 增加静态文件处理
- 整合主循环
- 本地验证说明
- 已知限制
说明项目目标、运行方式、技术原则和边界。
说明仅使用 Python 标准库,以及不使用高级框架的约束。
定义端口、编码、缓冲区大小、静态目录等常量。
说明请求报文和响应报文的基础结构,帮助理解后续解析逻辑。
完成 socket 创建、绑定、监听,并打印服务地址。
建立 accept 和 recv 的最小闭环,先看到请求,再谈解析。
将原始文本处理成结构化对象。
实现统一的响应报文拼接函数。
根据路径返回不同内容。
处理本地文件访问和 Content-Type 推断。
把前面所有函数串起来,形成可持续运行的服务。
说明如何在浏览器中访问、如何测试 404、如何验证静态文件。
列出单线程、阻塞式、协议支持不完整等约束。
Notebook 中建议形成一个统一的请求对象,用于在各处理阶段之间传递上下文。
建议字段包括:
methodraw_pathpathquery_stringquery_paramshttp_versionheadersraw_bytesraw_textclient_address
虽然不要求实现复杂类结构,但建议统一响应数据格式,至少在函数间保持如下信息一致:
status_codereason_phraseheadersbody
建议每个路由处理逻辑尽量保持单一职责,例如:
- 首页处理函数只返回首页内容
hello路由只负责返回简单文本- 静态文件处理函数只负责文件定位与读取
主循环至少应包含:
- 接收连接
- 读取请求
- 解析请求
- 分发路由
- 构建响应
- 发送响应
- 关闭连接
- 输出日志
本期建议采用简单策略:
- 每次请求处理完成后关闭连接
- 不优先支持 keep-alive
这样可以显著降低实现复杂度,保持核心逻辑可控。
首页应返回一个简单 HTML 页面,用于证明:
- 服务已成功启动
- 浏览器可以正常访问
- HTML 响应构建有效
页面内容不要求复杂,但应包含:
- 页面标题
- 服务运行提示
- 若干可访问路径说明
返回纯文本响应,用于验证:
- 文本类型响应
Content-Type: text/plain- 基础路由分发
返回另一段 HTML 或文本内容,用于验证多路由支持。
返回本地文件,用于验证:
- 文件路径映射
- 文件读取
- MIME 类型识别
- 二进制或文本内容发送
建议对 404 和 400 返回简洁但明确的内容,例如:
- 状态码
- 错误名称
- 简短说明
PRD 本身应满足:
- 结构完整
- 范围明确
- 交付形式明确
- 技术原则明确
- 实施路径明确
- 验收标准可执行
后续实现 Notebook 时,应满足以下最低验收条件:
- Notebook 能从头顺序执行
- 能成功启动本地服务
- 访问
/返回200 - 访问
/hello返回200 - 访问不存在路径返回
404 - 至少一个
/static/...资源可访问 - 能在 Notebook 输出中看到基本请求日志
- 不依赖任何高级 Web 框架
- 代码单元职责明确
- 没有把全部逻辑混在一个超长单元中
- 请求解析与响应构建是可单独理解的
- 错误分支至少覆盖
400与404
目标:
- 创建 socket
- 启动监听
- 接收一次请求
- 返回固定文本响应
完成标志:
- 浏览器访问后能收到基础响应
目标:
- 解析请求行
- 解析请求头
- 输出 method、path、version
完成标志:
- 根据不同路径识别请求目标
目标:
- 支持
/、/hello、/about - 路由未命中返回
404
完成标志:
- 访问不同路径得到不同响应
目标:
- 支持
/static/... - 返回本地文件内容
- 根据扩展名设置
Content-Type
完成标志:
- 浏览器可直接访问一个本地 HTML 或 CSS 文件
目标:
- 增加
400、404等错误响应 - 输出基础日志
- 完成 Notebook 的运行说明与限制说明
完成标志:
- Notebook 成为一个完整、可重复执行的项目成品
服务主循环在 Notebook 中启动后会持续运行,可能影响交互体验。需要在实现中明确说明中断方式。
现代浏览器发送的请求通常包含较多请求头,甚至可能发起额外资源请求。项目实现需要聚焦最关键字段,避免一开始试图完整覆盖所有浏览器行为。
静态文件服务如果路径拼接不严谨,容易出现目录穿越问题。因此静态文件处理必须在设计上优先考虑路径边界。
本项目不会在本期实现完整 HTTP 协议支持,因此:
- 只保证最基础的
GET场景 - 不承诺处理所有客户端边缘行为
- 不承诺兼容复杂长连接语义
阻塞式、单连接处理模式天然不适合高并发场景,因此本项目只追求实现清晰与正确性,不追求吞吐表现。
项目被视为成功的标准包括:
- 有一份足够详细、可直接执行后续开发的规划书
- 后续实现者无需再补总体架构即可开始构建 Notebook
- 项目目标、边界、实现顺序和验收方式全部明确
- “from scratch” 的约束在文档中得到清晰落实
- Notebook 作为唯一核心交付形态得到完整定义
在本期目标完成后,可以考虑的扩展包括:
- 支持
POST - 支持请求体读取
- 支持表单解析
- 支持 JSON 响应
- 支持更规范的响应头体系
- 支持更完善的 MIME 类型处理
- 支持目录索引页
- 支持简单模板渲染
- 支持多连接处理模型
- 支持更细粒度日志系统
本项目应被定义为一个基于 Jupyter Notebook 的、以 Python 标准库和底层 socket 能力为核心的 HTTP Server 构建项目。其重点不在于快速得到一个现成 Web 应用,而在于完整、透明、可观察地搭建出一个最小但结构完整的 HTTP 服务系统。
在实现过程中,必须始终坚持以下四点:
- 以
.ipynb作为核心交付物 - 以
socket和基础标准库作为主要技术手段 - 不引入高级 Web 框架作为核心实现
- 优先保证过程清晰、结构明确和可验证性
基于以上原则,本文档已给出完整的范围定义、模块拆解、结构设计、实施路径与验收标准,可直接作为后续 Notebook 实现的正式规划依据。