【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还没接触过。


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

相关文章
|
3天前
|
缓存 自然语言处理 数据库
构建高效Python Web应用:异步编程与Tornado框架
【5月更文挑战第30天】在追求高性能Web应用开发的时代,异步编程已成为提升响应速度和处理并发请求的关键手段。本文将深入探讨Python世界中的异步编程技术,特别是Tornado框架如何利用非阻塞I/O和事件循环机制来优化Web服务的性能。我们将剖析Tornado的核心组件,并通过实例演示如何构建一个高效的Web服务。
|
4天前
|
分布式计算 前端开发 Java
Java的web框架
Java的web框架
|
5天前
|
Web App开发 JavaScript 前端开发
构建高效Web API:使用Node.js与Express框架
构建高效Web API:使用Node.js与Express框架
11 0
|
9天前
|
机器学习/深度学习 分布式计算 数据处理
在Python中应用Spark框架
在Python中应用Spark框架
16 1
|
9天前
|
存储 设计模式 前端开发
Python Django框架总介绍
Python Django框架总介绍
10 0
|
10天前
|
机器学习/深度学习 数据处理 算法框架/工具
Python库与框架的深入解析
Python中的库和框架扩展了其功能,提高了开发效率。库(如标准库os和第三方库requests)提供预定义的工具,而框架(如Web框架Flask和数据科学框架Scikit-learn)定义了应用结构和交互方式。通过库和框架,开发者能更专注于业务逻辑,快速构建Web应用和执行数据科学任务。
|
12天前
|
设计模式 缓存 前端开发
Python Django框架
Python Django框架
|
13天前
|
JSON JavaScript API
Python进阶---FastAPI框架
Python进阶---FastAPI框架
37 2
|
13天前
|
网络协议 数据格式 Python
Python进阶---HTTP协议和Web服务器
Python进阶---HTTP协议和Web服务器
20 4
|
13天前
|
IDE Java 开发工具
初学 Python 需要安装哪些软件?超级实用,小白必看!_python框架下其他软件
初学 Python 需要安装哪些软件?超级实用,小白必看!_python框架下其他软件
初学 Python 需要安装哪些软件?超级实用,小白必看!_python框架下其他软件