Lab1 · 购物清单(Socket 手写服务器)
一句话:不用任何框架,用 socket 从零手写 HTTP 服务器,实现"待买 / 已买"两栏购物清单,全部靠表单提交 + 服务端渲染 + 整页刷新工作。 HTTP 报文结构:请求行 → 头(\r\n 分隔,空行结束)→ 体(长度由…
Cet article n'existe pour l'instant qu'en chinois. L'interface est traduite ; le texte suivra.
代码:
CSSE280 HW\280Lab\|所属课程:CSSE280 总览|进化版:Lab2 - 购物清单(Flask REST API)
一句话:不用任何框架,用 socket 从零手写 HTTP 服务器,实现"待买 / 已买"两栏购物清单,全部靠表单提交 + 服务端渲染 + 整页刷新工作。
文件结构
| 文件 | 作用 |
|---|---|
httpserver.py | 手写 HTTP 服务器:解析请求行/头/体,静态文件 + API 路由 |
dataservice.py | 数据层:to_get / gotten 两个 list,提供增删移动函数 |
public/shopping.html | 页面模板,含 {to_get} {got} 占位符 |
public/scripts/script.js | AJAX 练习 stub(未启用,HTML 里 script 标签被注释掉了) |
请求处理流程(httpserver.py 的骨架)
accept 连接 → 读请求行(方法 + 路径)→ parse_headers 逐行读到空行
→ 命中 API 路由?
├ GET /shopping.html → 读模板 + str.format 填入两栏列表 → 返回
├ POST /add_new_item → 解析表单体 → dataservice.add → 重新渲染整页
├ POST /item_added_to_cart → 移到"已买" → 重新渲染整页
└ POST /item_removed_from_cart → 移回"待买" → 重新渲染整页
→ 否则按扩展名查 Content-Type,直接回文件字节
→ 写响应头(状态行/Content-Type/Content-Length)+ 响应体 → 关连接
核心知识点
- HTTP 报文结构:请求行 → 头(
\r\n分隔,空行结束)→ 体(长度由Content-Length决定) - POST 表单体解析:
enctype="text/plain"用\r\n分行、=分键值;url-encoded 用&和= - 服务端渲染:
response_body.format(**fields)——列表项在 Python 里拼成<li><button>再塞进模板 - 每个
<li>是个提交按钮:<button name="item" value="milk">,点谁就提交谁,服务器据此移动条目 - 特殊路由
/shutdown可远程关服务器;time.sleep(2)故意加延迟模拟慢网络
注意 / 遗留问题
script.js是后续 AJAX 练习的半成品(XHR / jQuery / fetch 各写一个的 TODO),且有几处笔误:xhr.responseTex(少个 t)、responseData.to_get.array(多了.array)、toGetListElement()(元素被当函数调用)。当前页面不加载它,不影响运行——这些正是 Lab2 - 购物清单(Flask REST API) 里被正式实现的部分。
运行
cd "CSSE280 HW\280Lab"
python httpserver.py
# → http://localhost:8080/shopping.html