发布时间:2026/9/4 2:01:06
Python web编程教程(六) 第 3 章HTTP 协议详解 — 示例与习题摘要本章通过 4 个可运行的 Python 示例深入讲解 HTTP 协议的核心机制手动构造请求文本以理解报文结构、状态码分类与含义、使用requests库发送各类请求以及 Cookie 与 Session 的交互流程。文末附 5 道配套习题选择、填空、判断、实践及详细答案帮助读者巩固 HTTP 知识并提升实战能力。示例示例 1手动构造 HTTP 请求文本# 用 Python 字符串手动构造一个完整的 HTTP 请求# 帮助理解 HTTP 协议的结构defbuild_get_request(host,path,paramsNone,headersNone):构造 GET 请求文本# 拼接查询参数ifparams:query.join(f{k}{v}fork,vinparams.items())pathf{path}?{query}lines[fGET{path}HTTP/1.1,fHost:{host}]ifheaders:fork,vinheaders.items():lines.append(f{k}:{v})lines.append()# 空行分隔头和体lines.append()# GET 通常没有请求体return\r\n.join(lines)defbuild_post_request(host,path,bodyNone,content_typeapplication/json,headersNone):构造 POST 请求文本importjsonifisinstance(body,dict)andcontent_typeapplication/json:body_strjson.dumps(body)elifisinstance(body,dict):body_str.join(f{k}{v}fork,vinbody.items())else:body_strstr(body)ifbodyelselines[fPOST{path}HTTP/1.1,fHost:{host},fContent-Type:{content_type},fContent-Length:{len(body_str)},]ifheaders:fork,vinheaders.items():lines.append(f{k}:{v})lines.append()# 空行lines.append(body_str)return\r\n.join(lines)# 构造 GET 请求print( GET 请求 )print(build_get_request(localhost:5000,/api/users,params{page:1,per_page:10},headers{Accept:application/json,Authorization:Bearer abc123}))print(\n POST 请求 )print(build_post_request(localhost:5000,/api/users,body{username:小明,email:xmexample.com},content_typeapplication/json))输出 GET 请求 GET /api/users?page1per_page10 HTTP/1.1 Host: localhost:5000 Accept: application/json Authorization: Bearer abc123 POST 请求 POST /api/users HTTP/1.1 Host: localhost:5000 Content-Type: application/json Content-Length: 48 {username: \u5c0f\u660e, email: xmexample.com}示例 2状态码判断工具definterpret_status(code):解释 HTTP 状态码ranges{range(100,200):信息响应,range(200,300):成功响应,range(300,400):重定向,range(400,500):客户端错误,range(500,600):服务端错误,}descriptions{200:OK - 请求成功,201:Created - 资源创建成功,204:No Content - 无内容删除成功,301:Moved Permanently - 永久重定向,302:Found - 临时重定向,304:Not Modified - 资源未修改,400:Bad Request - 请求参数有误,401:Unauthorized - 未认证,403:Forbidden - 无权限,404:Not Found - 资源不存在,405:Method Not Allowed - 方法不允许,409:Conflict - 冲突,422:Unprocessable Entity - 验证失败,500:Internal Server Error - 服务器内部错误,502:Bad Gateway - 网关错误,503:Service Unavailable - 服务不可用,504:Gateway Timeout - 网关超时,}categorynext((vforr,vinranges.items()ifcodeinr),未知)descdescriptions.get(code,未知状态码)# 判断是客户端还是服务端的问题if400code500:blame客户端的问题elif500code600:blame服务器的问题else:blamereturnf{code}[{category}]{desc}{blame}# 测试各种状态码test_codes[200,201,301,400,401,403,404,409,422,500,503]forcodeintest_codes:print(interpret_status(code))输出200 [成功响应] OK - 请求成功 201 [成功响应] Created - 资源创建成功 301 [重定向] Moved Permanently - 永久重定向 400 [客户端错误] Bad Request - 请求参数有误 客户端的问题 401 [客户端错误] Unauthorized - 未认证 客户端的问题 403 [客户端错误] Forbidden - 无权限 客户端的问题 404 [客户端错误] Not Found - 资源不存在 客户端的问题 409 [客户端错误] Conflict - 冲突 客户端的问题 422 [客户端错误] Unprocessable Entity - 验证失败 客户端的问题 500 [服务端错误] Internal Server Error - 服务器内部错误 服务器的问题 503 [服务端错误] Service Unavailable - 服务不可用 服务器的问题示例 3用 requests 发送各种请求importrequests BASE_URLhttps://httpbin.org# 1. GET 请求带查询参数defdemo_get():print( GET 请求 )resprequests.get(f{BASE_URL}/get,params{name:小明,age:18})print(f状态码:{resp.status_code})print(f响应类型:{resp.headers[Content-Type]})print(f服务器收到的参数:{resp.json()[args]})print()# 2. POST 请求发送 JSONdefdemo_post_json():print( POST JSON 请求 )resprequests.post(f{BASE_URL}/post,json{title:Flask 入门,content:Flask 是一个轻量级框架})print(f状态码:{resp.status_code})print(f服务器收到的 JSON:{resp.json()[json]})print()# 3. POST 请求发送表单defdemo_post_form():print( POST 表单请求 )resprequests.post(f{BASE_URL}/post,data{username:admin,password:123456})print(f状态码:{resp.status_code})print(fContent-Type:{resp.json()[headers][Content-Type]})print(f服务器收到的表单:{resp.json()[form]})print()# 4. 自定义请求头defdemo_custom_headers():print( 自定义请求头 )resprequests.get(f{BASE_URL}/headers,headers{User-Agent:MyPythonBot/1.0,X-Custom-Header:Hello-World,Authorization:Bearer my-token-123})print(f状态码:{resp.status_code})sent_headersresp.json()[headers]forkeyin[User-Agent,X-Custom-Header,Authorization]:print(f 发送的{key}:{sent_headers.get(key,N/A)})print()# 5. 处理错误响应defdemo_error_handling():print( 错误处理 )test_status[200,400,404,500]forstatusintest_status:resprequests.get(f{BASE_URL}/status/{status})ok✓ 成功ifresp.okelse✗ 失败print(f 请求 /status/{status}- 状态码{resp.status_code}{ok})print()# 运行所有示例demo_get()demo_post_json()demo_post_form()demo_custom_headers()demo_error_handling()示例 4模拟 Cookie 和 Session 流程# 用代码模拟理解 Cookie 和 Session 的交互流程classMockSession:模拟服务器端 Session 存储def__init__(self):self._data{}defcreate(self,user_id,username):importuuid session_idstr(uuid.uuid4())[:8]self._data[session_id]{user_id:user_id,username:username}returnsession_iddefget(self,session_id):returnself._data.get(session_id)defdelete(self,session_id):ifsession_idinself._data:delself._data[session_id]returnTruereturnFalseclassMockBrowser:模拟浏览器存储 Cookiedef__init__(self):self.cookies{}defset_cookie(self,key,value):self.cookies[key]valuedefget_cookie(self,key):returnself.cookies.get(key)defclear_cookies(self):self.cookies.clear()# 模拟登录流程server_sessionMockSession()browserMockBrowser()print( 1. 用户登录 )# 服务器验证成功后创建 Sessionsession_idserver_session.create(user_id1,username小明)# 服务器通过 Set-Cookie 返回 session_idbrowser.set_cookie(session_id,session_id)print(f 服务器创建 Session:{session_id})print(f 浏览器保存 Cookie:{browser.cookies})print(\n 2. 后续请求 )# 浏览器每次请求自动带上 Cookiesidbrowser.get_cookie(session_id)user_dataserver_session.get(sid)ifuser_data:print(f 服务器根据 session_id{sid}找到用户:{user_data})else:print( 未找到用户信息)print(\n 3. 用户退出 )sidbrowser.get_cookie(session_id)server_session.delete(sid)browser.clear_cookies()print(f 服务器删除 Session)print(f 浏览器清除 Cookie:{browser.cookies})print(\n 4. 退出后请求 )sidbrowser.get_cookie(session_id)user_dataserver_session.get(sid)print(f Session:{user_data})print(f 结论: 用户已退出需要重新登录)输出 1. 用户登录 服务器创建 Session: a1b2c3d4 浏览器保存 Cookie: {session_id: a1b2c3d4} 2. 后续请求 服务器根据 session_ida1b2c3d4 找到用户: {user_id: 1, username: 小明} 3. 用户退出 服务器删除 Session 浏览器清除 Cookie: {} 4. 退出后请求 Session: None 结论: 用户已退出需要重新登录习题习题 1选择题HTTP 状态码405表示什么含义A. 资源不存在B. 请求方法不允许C. 未认证D. 服务器内部错误HTTP 常用方法对比在实际开发中不同的 HTTP 方法对应不同的语义和用途。下表汇总了最常用的几种方法帮助你快速区分它们的作用、是否携带请求体、幂等性以及典型的成功状态码方法作用是否携带请求体幂等性典型状态码GET读取资源否幂等200 OKPOST创建资源是非幂等201 CreatedPUT整体更新资源是幂等200 OKPATCH部分更新资源是非幂等200 OKDELETE删除资源否幂等204 No Content说明幂等Idempotent指无论执行一次还是多次对服务器资源产生的最终效果都相同。GET、PUT、DELETE 都是幂等操作——重复发送不会产生额外副作用而 POST 每次都会创建新资源PATCH 每次可能基于当前状态做增量修改因此二者都是非幂等的。理解这些差异有助于在接口设计中选用合适的方法。习题 2选择题以下哪种 HTTP 方法通常用于创建新资源A. GETB. POSTC. PUTD. DELETE习题 3填空题HTTP 请求由请求行、请求头、空行和请求体四部分组成。其中请求行包含三个信息、和协议版本。习题 4判断题GET 请求的参数放在请求体中POST 请求的参数放在 URL 中。 习题 5实践题使用requests库编写一个脚本完成以下任务向https://httpbin.org/get发送 GET 请求带参数name你的名字coursepython向https://httpbin.org/post发送 POST 请求发送 JSON 数据{title: test, content: hello}向https://httpbin.org/status/404发送请求判断状态码并打印是客户端错误还是服务端错误打印每个请求的响应时间答案习题 1 答案B. 请求方法不允许解析405 Method Not Allowed 表示服务器支持该 URL但不支持该 HTTP 方法。例如对一个只接受 GET 的路由发送 POST 请求会返回 405。习题 2 答案B. POST解析POST 用于创建新资源返回 201 Created。PUT 用于更新已有资源。GET 用于读取DELETE 用于删除。习题 3 答案请求方法请求路径URL解析请求行格式为方法 路径 协议版本如GET /api/users HTTP/1.1。习题 4 答案错误×解析正好相反。GET 请求的参数放在 URL 查询字符串中如?name小明POST 请求的参数放在请求体中。习题 5 答案importrequests BASEhttps://httpbin.org# 1. GET 请求print( 1. GET 请求 )resprequests.get(f{BASE}/get,params{name:小明,course:python})print(f状态码:{resp.status_code})print(f响应时间:{resp.elapsed.total_seconds():.3f}秒)print(f服务器收到的参数:{resp.json()[args]})print()# 2. POST 请求print( 2. POST 请求 )resprequests.post(f{BASE}/post,json{title:test,content:hello})print(f状态码:{resp.status_code})print(f响应时间:{resp.elapsed.total_seconds():.3f}秒)print(f服务器收到的 JSON:{resp.json()[json]})print()# 3. 404 状态码print( 3. 404 状态码 )resprequests.get(f{BASE}/status/404)print(f状态码:{resp.status_code})print(f响应时间:{resp.elapsed.total_seconds():.3f}秒)if400resp.status_code500:print(这是客户端错误4xx)elif500resp.status_code600:print(这是服务端错误5xx)print()# 4. 对比不同状态码的响应时间print( 4. 状态码对比 )forcodein[200,400,404,500]:resprequests.get(f{BASE}/status/{code})category成功ifresp.okelse\客户端错误if400code500else服务端错误print(f /status/{code}-{resp.status_code}[{category}] ({resp.elapsed.total_seconds():.3f}秒))

相关新闻

2026/9/4 1:56:06

MiniMax H3一键整合包深度拆解:环境、提示词与加速

如果你最近也被“MiniMax H3 一键整合包”这类标题刷到过,你大概会在下载按钮前犹豫一下。标题把最抓人的词都用上了:一键、整合、1000提示词、首个加速插件、900%提速,甚至还有“1000s到120s的救赎”。这一串词放在一起确实很有吸引力。但我…

2026/9/4 1:56:06

OpenCV+Python车牌识别工程实践:从预处理到轻量部署

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/4 1:56:06

汽车前/后/侧三向检测数据集:VOC+YOLO双格式5319张图

简介:本资源是面向计算机视觉初学者与智能交通算法开发者的目标检测专用数据集,聚焦汽车头部与尾部关键部件识别任务,适用于YOLO系列、Faster R-CNN等主流模型的训练与验证。数据集共5319张高质量JPEG图像,配套同等数量的Pascal V…

2026/9/4 2:46:10

7.9 C++实战100例——完美转发与初始化列表的冲突

7.9 C++实战100例——完美转发与初始化列表的冲突 ——用 nm -C 追踪 std::initializer_list 类型推导失败,std::make_unique 与 {} 的不可调和矛盾 C++ 踩坑排雷手册 总纲目录与逻辑索引 1.1 构造完成前对象不存在:构造函数体内调用虚函数不会按派生类分发 1.2 对象切片:…

2026/9/4 2:46:10

7.8 C++实战100例——移动后析构函数需处理空状态

7.8 C++实战100例——移动后析构函数需处理空状态 ——用 GDB 断点追踪移动后源对象的析构路径,定位双重释放或空指针解引用 C++ 踩坑排雷手册 总纲目录与逻辑索引 1.1 构造完成前对象不存在:构造函数体内调用虚函数不会按派生类分发 1.2 对象切片:将派生类按值赋给基类,…

2026/9/4 2:46:10

舰船ISAR距离对准:动态补偿原理与MATLAB工程实现

简介:本资源聚焦逆合成孔径雷达(ISAR)成像中的关键预处理环节——舰船目标的距离对准,面向电子信息工程、信号与信息处理、雷达系统等方向的本科生及研究生,适用于课程设计、期末大作业与毕业设计等实践场景。压缩包共…

2026/9/4 2:46:10

DeepSeek接入实战:API调用、本地部署与编程工具配置

“黑鲸出水,DeepSeek 下半场开始”——这句话听起来像行业点评,但从工程视角看,真正的变化是接入方式变了:网页对话只能验证模型本身,API 和开源权重才能验证工具链。最近在 Codex、Claude Code、Cline、CC Switch 等工…

2026/9/4 2:46:10

USRP B210 FPGA开发实战:Verilog源码解析与硬件加速信号处理

简介:本资源为USRP B210设备的完整FPGA底层开发套件,面向软件定义无线电(SDR)领域的硬件工程师、通信系统开发者及FPGA进阶学习者,用于深入理解射频前端控制、数字下变频(DDC)、数据流调度等关键…

2026/9/4 2:41:10

Matlab机械臂末端轨迹规划课程设计解剖指南

简介:本资源是一份面向高校自动化、机器人工程及控制科学等相关专业本科生的机械臂末端轨迹规划课程设计实践材料,聚焦于MATLAB平台下的运动学建模与轨迹生成核心问题,适用于课程设计、期末大作业及仿真实验环节。压缩包共含若干文件&#xf…

2026/9/3 18:28:26

vSound小提琴数字处理器实操指南:从接线到演出的完整配置

电小提琴或者原声小提琴插电演出,第一个绕不开的坎就是声音难听。原声琴的共鸣和空气感一旦进了拾音器,出来的往往是一坨干瘪、发尖、带着奇怪塑料味的信号。我当初第一次把琴接上乐队调音台,直接被主唱吐槽"你这声音像在锯钢丝"。…

2026/9/3 14:29:47

传感器接口IC如何攻克生物化学传感的微弱信号难题?

1. 从电极到比特流:为什么生物化学传感必须依赖专用接口IC 做生物化学传感的人都有过类似的经历:明明传感器本身性能很好,信号输出却一塌糊涂——噪声大、漂移明显、重复性差,怎么调都达不到预期。很多时候问题并不在传感器&#…

2026/9/3 14:30:35

STM32F411CEU6多通道ADC采集:扫描模式+DMA实现详解

1. 多通道 ADC 的用武之地把“Multichannel ADC”和“STM32F411CEU6”这两个关键字放在一起,其实就是嵌入式开发里最常遇到的一类需求:用一块不算贵的 MCU,同时采集多路模拟信号。STM32F411CEU6 是 48 引脚的 Cortex-M4F 主控,主频…

2026/9/4 0:00:58

STM32H743 SPI从机DMA双缓冲通信实战

简介:本资源是面向嵌入式开发工程师与STM32进阶学习者的SPI DMA双机通信从机端完整实现方案,聚焦STM32H743高性能Cortex-M7单片机在工业控制与高速数据交互场景下的从机通信开发痛点。压缩包含1355个文件,主体为599个C源码与321个头文件&…

2026/9/4 0:00:58

CPU开盖降温教程:20元成本让温度直降30度的原理与实践

最近很多朋友都在抱怨,自己的电脑一到夏天就变成"烤箱",玩游戏时CPU温度动不动就飙到90度以上,风扇噪音堪比直升机。更让人头疼的是,明明配置不错,却因为高温降频导致性能大打折扣。如果你也遇到了类似问题&…

2026/9/4 0:00:58

ArkTS 表单工程:场地预约页的三态场次 Grid 与校验

ArkTS 表单工程:场地预约页的三态场次 Grid 与校验 App 14「运动场地预约」场地 Tab(Func1Tab),是整 App 交互最丰富的页面——场地横向切换 三色图例 渐变预约预览卡 快捷模板 今日场次 Grid(可选/已选/已满三态&…

2026/9/3 20:43:36

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/3 17:51:43

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/3 21:06:57

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…