【Python】简单Web框架从零开始(二):Http请求格式

简介: 一、前言 上一篇文章已经搭建了一个简单的http的网络服务器,可以接收浏览器的请求并简单响应。这期开始介绍http协议的具体格式以及如何解析,通过理解http的协议格式,就可以正确识别出客户端的请求内容,并根据对应的处理方法做出正确的响应。

【Python】简单Web框架从零开始(二):Http请求格式


目录


【Python】简单Web框架从零开始(一):Web服务


一、前言


   上一篇文章已经搭建了一个简单的http的网络服务器,可以接收浏览器的请求并简单响应。这期开始介绍http协议的具体格式以及如何解析,通过理解http的协议格式,就可以正确识别出客户端的请求内容,并根据对应的处理方法做出正确的响应。


二、HTTP请求格式介绍


   为了可以快速掌握,可以启动第一期的服务程序,然后通过浏览器访问对应的地址(http://127.0.0.1,服务器会在接收到客户端数据后将其打印出来,从而方便的进行结构分析。


微信截图_20220424002746.png

图1


   图1展示了浏览器访问http://127.0.0.1/地址的请求数据内容,具体内容解释如下:


       1. 第一行为请求行包含:请求方法(本图为GET),访问服务器的地址路径(本图为根路径/),HTTP的版本(本图为1.1),这3个数据之间使用空格分隔开。


       2. 中间为实体头信息包含通用头信息、请求头信息、实体头信息。其中部分是客户端的相关信息及功能支持情况,还有一些特殊的例如CookieCache相关的信息。


       3. 最后会有一个空行(\r\n)表示实体头内容的结束标记。


       4. 请求数据体,本图中由于没有任何额外的数据,因此没有后续内容输出。


微信截图_20220424002755.png

图2


   图2展示了浏览器带参数的请求,请求地址为http://127.0.0.1/test?username=abc&password=123456。其他内容都是和图1差不多一样的,注意后面的空行是存在的。这种请求的方式参数都显示在url地址中,如果参数够多整个url就非常的长长长


微信截图_20220424002815.png

图3


   图3展示了浏览器POST带参数请求,请求地址为http://127.0.0.1/test,参数数据存放在实体头的后面即请求数据体,参数的数据格式与图3放在地址中的内容是一样的,这样就可以让url看起来简单,并且“隐藏”参数信息。注意这里实体头里面有一个Content-Length属性数据表示后面HTTP数据体的长度,Content-Type属性表示HTTP数据体的格式类型。


微信截图_20220424002829.png

图4


   图4是另一种格式的POST请求,Content-Typemultipart/form-data,并且额外带有boundary的属性值。HTTP数据体的内容格式稍微复杂了一些,采用[--boundary]进行分割,并对每个参数可以额外指定类型,包括支持上传文件。


微信截图_20220424002837.png

图5


   图5是访问静态文件的请求格式,与图1基本一致,只是地址中包含了要请求下载的文件名和文件格式,服务器只需要按照正确的格式将需要的静态文件内容发送给客户端就可以完成下载。


   下图是完整的HTTP请求格式说明:


微信截图_20220424002849.png


三、解析HTTP请求


   快速理解客户端请求的格式后,就可以进行请求数据解析。每条连接发送请求数据后,服务器读取数据并开始进行解析,然后调用对应的处理方法后返回正确的响应数据就可以完成交互通讯。


   1. 从首行内容解析开始,利用了将socket的recv方式改为文件的read方式,可以简化处理过程,如下代码:


# 使用文件的方式操作socket
rfile = self.sock.makefile() #mode="r" 读取 "w"写入
# 解析第一行
first_line = rfile.readline()
# GET/POST/HEAD url&args HTTP/1.1
method_location_version = first_line.split()


   2. 实体头内容格式是固定的,每一行格式为:[name]:[空格][数据][\r\n] 表示属性name的对应数据值,部分数据值需要继续拆分。实体头内容完后会跟着一个独立的空行[\r\n]。可以以这个作为实体头结束的标记


while True:
    line = fd.readline().strip()
    if not line :
         break
    name_value = line.split(": ", 1)
    if not name_value or len(name_value) != 2:
        break # error format
    name = name_value[0]
    value = name_value[1]
    self.request_headers[name] = value.strip()


   3. 最后就是解析参数了,类似uesrname=abc&password=123456这样的格式可以使用urlparse.parse_qs进行解析成一个字典{"username"=["abc"],"password"=["123456"]},但multipart/form-data格式的解析就需要自己实现,我在自带库没有找到相关的解析方法,如果有知道的希望可以告诉我一下


# url中存放参数 /xxxx?a=v1&b=v2...
index = self.request_route.find("?")
if index > 0 and len(self.request_route) > index:
    arguments = urlparse.parse_qs(self.request_route[index+1:])
    self.request_arguments.update(arguments)
# 解析请求内容的格式
form_str_type = self.request_headers.get("Content-Type", None)
if not form_str_type:
    return  # 如果没有指定类型则不理会了
# 将参数放在正文中,但格式和放在url里面的一样
if form_str_type.find("application/x-www-form-urlencoded") >= 0:
    arguments = urlparse.parse_qs(self.raw_body_data)
    self.request_arguments.update(arguments)
# 将参数放在正文中,采用多附件表单格式
elif form_str_type.find("multipart/form-data") >= 0:
    boundary_index = form_str_type.rfind("boundary=")
    if boundary_index < 0:
        print("Invalid multipart/form-data: no boundary")
        return
    arguments = self.parse_multipart_formdata(form_str_type[boundary_index+len("boundary="):])
    self.request_arguments.update(arguments)


四、后记


   截至目前介绍了http服务的创建和客户端请求格式的解析,接下来会继续介绍http响应的格式以及如何处理客户端的请求,从而真正完成网站的基本交互逻辑。另外我实现的这个简单web框架仅支持HTTP/1.0和HTTP/1.1的请求,最新的HTTP/2还没接触过。


欢迎微信搜索"游戏测试开发"关注一起沟通交流。

相关文章
|
11月前
|
SQL 自然语言处理 数据库
【Azure Developer】分享两段Python代码处理表格(CSV格式)数据 : 根据每列的内容生成SQL语句
本文介绍了使用Python Pandas处理数据收集任务中格式不统一的问题。针对两种情况:服务名对应多人拥有状态(1/0表示),以及服务名与人名重复列的情况,分别采用双层for循环和字典数据结构实现数据转换,最终生成Name对应的Services列表(逗号分隔)。此方法高效解决大量数据的人工处理难题,减少错误并提升效率。文中附带代码示例及执行结果截图,便于理解和实践。
288 4
|
10月前
|
Python
使用Python实现multipart/form-data文件接收的http服务器
至此,使用Python实现一个可以接收 'multipart/form-data' 文件的HTTP服务器的步骤就讲解完毕了。希望通过我的讲解,你可以更好地理解其中的逻辑,另外,你也可以尝试在实际项目中运用这方面的知识。
473 69
|
8月前
|
Linux 数据库 数据安全/隐私保护
Python web Django快速入门手册全栈版,共2590字,短小精悍
本教程涵盖Django从安装到数据库模型创建的全流程。第一章介绍Windows、Linux及macOS下虚拟环境搭建与Django安装验证;第二章讲解项目创建、迁移与运行;第三章演示应用APP创建及项目汉化;第四章说明超级用户创建与后台登录;第五章深入数据库模型设计,包括类与表的对应关系及模型创建步骤。内容精炼实用,适合快速入门Django全栈开发。
377 1
|
10月前
|
中间件 Go
Golang | Gin:net/http与Gin启动web服务的简单比较
总的来说,`net/http`和 `Gin`都是优秀的库,它们各有优缺点。你应该根据你的需求和经验来选择最适合你的工具。希望这个比较可以帮助你做出决策。
513 35
|
10月前
|
数据采集 人工智能 测试技术
Python有哪些好用且实用的Web框架?
Python 是一门功能强大的编程语言,在多个领域中得到广泛应用,包括爬虫、人工智能、游戏开发、自动化测试和 Web 开发。在 Web 开发中,Python 提供了多种框架以提高效率。以下是几个常用的 Python Web 框架:1) Django:开源框架,支持多种数据库引擎,适合新手;2) Flask:轻量级框架,基于简单核心并通过扩展增加功能;3) Web2py:免费开源框架,支持快速开发;4) Tornado:同时作为 Web 服务器和框架,适合高并发场景;5) CherryPy:简单易用的框架,连接 Web 服务器与 Python 代码。这些框架各有特色,可根据需求选择合适的工具。
532 14
|
12月前
|
数据采集 Web App开发 存储
打造高效的Web Scraper:Python与Selenium的完美结合
本文介绍如何使用Python结合Selenium,通过代理IP、设置Cookie和User-Agent抓取BOSS直聘的招聘信息,包括公司名称、岗位、要求和薪资。这些数据可用于行业趋势、人才需求、企业动态及区域经济分析,为求职者、企业和分析师提供宝贵信息。文中详细说明了环境准备、代理配置、登录操作及数据抓取步骤,并提醒注意反爬虫机制和验证码处理等问题。
340 1
打造高效的Web Scraper:Python与Selenium的完美结合
|
11月前
|
机器学习/深度学习 开发框架 API
Python 高级编程与实战:深入理解 Web 开发与 API 设计
在前几篇文章中,我们探讨了 Python 的基础语法、面向对象编程、函数式编程、元编程、性能优化、调试技巧以及数据科学和机器学习。本文将深入探讨 Python 在 Web 开发和 API 设计中的应用,并通过实战项目帮助你掌握这些技术。
|
缓存 网络协议 前端开发
Web 性能优化|了解 HTTP 协议后才能理解的预加载
本文旨在探讨和分享多种预加载技术及其在提升网站性能、优化用户体验方面的应用。
Web 性能优化|了解 HTTP 协议后才能理解的预加载
|
JSON 安全 中间件
Python Web 框架 FastAPI
FastAPI 是一个现代的 Python Web 框架,专为快速构建 API 和在线应用而设计。它凭借速度、简单性和开发人员友好的特性迅速走红。FastAPI 支持自动文档生成、类型提示、数据验证、异步操作和依赖注入等功能,极大提升了开发效率并减少了错误。安装简单,使用 pip 安装 FastAPI 和 uvicorn 即可开始开发。其优点包括高性能、自动数据验证和身份验证支持,但也存在学习曲线和社区资源相对较少的缺点。
589 15
|
4月前
|
算法 Java Go
【GoGin】(1)上手Go Gin 基于Go语言开发的Web框架,本文介绍了各种路由的配置信息;包含各场景下请求参数的基本传入接收
gin 框架中采用的路优酷是基于httprouter做的是一个高性能的 HTTP 请求路由器,适用于 Go 语言。它的设计目标是提供高效的路由匹配和低内存占用,特别适合需要高性能和简单路由的应用场景。
395 4

推荐镜像

更多