PythonWeb开发基础(三)类Flask框架请求封装

news/2024/11/25 7:48:47/

课程地址:Python 工程师进阶技术图谱

文章目录

  • 类Flask框架请求封装
    • HTTP请求解析的python实现
      • 1、解析查询字符串
      • 2、多值问题
    • 使用webob库解析请求
    • Bug记录
      • bug:AttributeError: module 'cgi' has no attribute 'parse_qs'


类Flask框架请求封装

Web服务器

  • 本质是个TCP服务器,监听在特定端口上
  • 支持HTTP协议,能够将HTTP请求报文进行解析,能够把响应数据进行HTTP协议的报文封装并返回浏览器端。

APP程序内部也可以请求其它Server,此时就是代理作用。总之,app里面就可以实现各种复杂的功能,只要最后满足WSGI的要求就行。

上一节中实现的app,不论收到什么反馈,都产生一样的响应,这一节将尝试对请求进行解析

HTTP请求解析的python实现

1、解析查询字符串

查询字符串

  • ?name=tom&id=1000,不同的参数之间使用&分隔开。

代码

from wsgiref.simple_server import make_serverdef simple_app(environ:dict, start_response):# 读取“请求方法”和“查询字符串”,并提前查询字符串中的信息method = environ.get('REQUEST_METHOD')print(method)query_string = environ.get('QUERY_STRING')print(query_string)# 解析查询字符串d = {}for item in query_string.split('&'):k,_,v = item.partition('=')d[k] = vprint(d)status = '200 OK'headers = [('Content-type', 'text/plain; charset=utf-8')]start_response(status, headers)ret = [query_string.encode('utf-8')]return ret  # 报文的正文部分,即网页内容with make_server('0.0.0.0', 9000, simple_app) as httpd:print("Serving on port 9000...")try:httpd.serve_forever()except Exception as e:print(e)except KeyboardInterrupt:print('stop')httpd.server_close()

然后使用我Edge的Postwoman工具发起一个GET请求,url为http://127.0.0.1:9000/?name=tom&id=1000

程序在python端就输出解析的查询字符串(第三行),我们将它解析成了一个字典

'''
GET
name=tom&id=1000&age=20
{'name': 'tom', 'id': '1000'}
'''

对于解析查询字符串的一段代码也可以使用下面两种写法,更加简单(行数更少,但感觉可读性不太好):

d = {k:v for k, _, v in map(lambda x:x.partition('='), query_string.split('&'))}
d = {k:v for k, _, v in [item.partition('=') for item in query_string.split('&')]}

或者使用库:

from urllib.parse import parse_qs
qs = parse_qs(query_string)

改用库后,再次发起请求,python端输出解析后的字典:

'''
{'name': ['tom'], 'id': ['1000']}
'''

2、多值问题

此时字典中的value值变成了一个列表,这是因为在url中可以对一个参数传入多值,例如将我们请求的url改成http://127.0.0.1:9000/?name=tom&id=1000&id=666,python端的输出将变成:

{'name': ['tom'], 'id': ['1000', '666']}

使用webob库解析请求

前面,我们获取请求的信息还需要记下信息的名称

method = environ.get('REQUEST_METHOD')

这显然十分麻烦。而使用webob库,我们可以通过对象的属性来访问请求的信息,只需将environ参数传给webob库中的Request对象,就可以自动实现解析。代码如下:

from wsgiref.simple_server import make_server
from webob import Requestdef simple_app(environ:dict, start_response):request = Request(environ)query_string = request.query_stringmethon = request.methodprint('methon, query_string: ', methon, query_string)print('request: ', request.GET) # 来自查询字符串的参数print('type(request.GET): ', type(request.GET)) # dictprint('request.POST: ', request.POST) # 来自POST的参数print('request.params: ', request.params) # 所有的参数,包含url的查询字符串,和POST的正文print('request.path: ', request.path)print('request.headers: ', request.headers) # 请求头status = '200 OK'headers = [('Content-type', 'text/plain; charset=utf-8')]start_response(status, headers)ret = [query_string.encode('utf-8')]return ret  # 报文的正文部分,即网页内容with make_server('0.0.0.0', 9000, simple_app) as httpd:print("Serving on port 9000...")try:httpd.serve_forever()except Exception as e:print(e)except KeyboardInterrupt:print('stop')httpd.server_close()

我使用Postwoman测试工具发送了一个POST请求,它url的查询字符串中有参数,POST也传输了一个参数age

在这里插入图片描述

下面是python端的输出

'''
Serving on port 9000...
methon, query_string:  POST name=tom&id=1000&id=666
request:  GET([('name', 'tom'), ('id', '1000'), ('id', '666')])
type(request.GET):  <class 'webob.multidict.GetDict'>
request.POST:  MultiDict([('age', '20')])
request.params:  NestedMultiDict([('name', 'tom'), ('id', '1000'), ('id', '666'), ('age', '20')])
request.path:  /
request.headers:  <webob.headers.EnvironHeaders object at 0x000002A24D1D1F00>
'''

Bug记录

bug:AttributeError: module ‘cgi’ has no attribute ‘parse_qs’

错误代码如下

from cgi import parse_qs
qs = parse_qs(query_string)

点进cgi的库查找parse_qs,发现了下面这段代码:

if sys.version_info < (3, 8):def parse_qs(qs: str, keep_blank_values: bool = ..., strict_parsing: bool = ...) -> dict[str, list[str]]: ...def parse_qsl(qs: str, keep_blank_values: bool = ..., strict_parsing: bool = ...) -> list[tuple[str, str]]: ...if sys.version_info >= (3, 7):def parse_multipart(fp: IO[Any], pdict: SupportsGetItem[str, bytes], encoding: str = ..., errors: str = ..., separator: str = ...) -> dict[str, list[Any]]: ...

显然,当sys.version_info>=(3,8)sys.version\_info >= (3, 8)sys.version_info>=(3,8)的时候,函数parse_qs是不会被定义的。应该是python版本的问题,我换成python3.7版本时,就可以正常运行了。

其实,cgi库已经过期了,使用urllib库就好。



http://www.ppmy.cn/news/22808.html

相关文章

Vue2与Vue3共存于一台电脑 保姆级教程

文章目录前言一、共存的前置条件二、共存的操作步骤三、最后一步&#xff0c;配置环境变量&#xff0c;实现全局调用四、 使用vue3报错前言 本文讲解了如何在一台电脑上使vue-cli2.x与vue-cli3.x共存&#xff0c;如果本文对你有所帮助请三连支持博主&#xff0c;感谢各位的支持…

正大国际期货:做恒指要懂得顺势而为

做恒指&#xff0c;究竟是应该做长线还是做短线&#xff0c;想必是一个有较大争议的话题。当然&#xff0c;选择短线操作是绝大多数人的选择&#xff0c;长线操作者在这个市场是寥寥无几的。说起恒指期货操作方法&#xff0c;其实很简单&#xff0c;那就是&#xff1a;做恒指要…

Unity三体运行模拟体验

Unity三体运行模拟体验 这两天看完三体电视剧&#xff0c;很想体验一把三体人的世界…于是&#xff0c;说干就干。 先来看看效果吧 先来个上帝视角的 Unity三体模拟上帝视角然后再来个三体人视角的&#xff08;行星视角&#xff09;Unity三体运行模拟&#xff08;行星视角上…

国产高清卫星影像时代来了,打造中国版“谷歌地球”!

随着国家数字化战略转型进程不断加快&#xff0c;卫星遥感影像作为基础数据&#xff0c;应用越来越广泛。目前已经成为资源环境调查、监测、评价和管理等不可或缺的技术手段。 不止于此&#xff0c;在推动行业发展、提高生产力以及节约成本等方面&#xff0c;卫星遥感影像都实…

houdini 程序化 序

程序化不单单只是houdini。 houdini是一个软件&#xff0c;程序化是处理问题的方法&#xff0c;两者不可混为一谈。 为什么都喜欢用houdini做程序化&#xff1f; 节点式&#xff0c;对美术友好。功能强大&#xff0c;运算速度快HDA&#xff0c;让功能不局限于houdini开发方便…

华为云之HECS云服务器配置docker环境

华为云之HECS云服务器配置docker环境一、华为HECS云服务器介绍二、SSH登录HECS云服务器三、检查HESC环境1.检查系统版本2.检查VPC本地IP地址四、配置yum仓库1.备份yum仓库2.配置阿里仓库源3.配置epel源4.配置docker源①安装系统工具②配置docker源5.生成缓存6.列出yum源五、安装…

【王道数据结构】第五章(上) | 树 | 二叉树

目录 一、树 1、树的基本概念 2、非空树特点&#xff1a; 3、基本术语 4、树的常考性质 二、二叉树 1、二叉树的定义 2、几种特殊的二叉树 3、二叉树的常考性质 4、二叉树的存储结构 5、二叉树的遍历 6、由遍历序列构造二叉树 7、线索二叉树 一、树 1、树的基本概…

C进阶_位段

目录 什么是位段 位段的内存分配 位段的跨平台问题 位段的应用 什么是位段 位段的声明和结构体是类似的&#xff0c;有两个不同&#xff1a; 1.位段的成员必须是int、unsigned int或signed int。 2.位段的成员名后边有一个冒号和一个数字。 比如&#xff1a; struct A …