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

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

类Flask框架请求封装

Web服务器

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

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

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

HTTP请求解析的python实现

1、解析查询字符串

查询字符串

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

代码

from wsgiref.simple_server import make_server
def 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] = v
    print(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 Request
def simple_app(environ:dict, start_response):
    request = Request(environ)
    query_string = request.query_string
    methon = request.method
    print('methon, query_string: ', methon, query_string)
    print('request: ', request.GET) # 来自查询字符串的参数
    print('type(request.GET): ', type(request.GET)) # dict
    print('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

5930290a271d4c41b8c660e22a889a8b.png

下面是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)的时候,函数parse_qs是不会被定义的。应该是python版本的问题,我换成python3.7版本时,就可以正常运行了。


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

相关文章
|
18天前
|
安全 数据库 C++
Python Web框架比较:Django vs Flask vs Pyramid
【4月更文挑战第9天】本文对比了Python三大Web框架Django、Flask和Pyramid。Django功能全面,适合快速开发,但学习曲线较陡;Flask轻量灵活,易于入门,但默认配置简单,需自行添加功能;Pyramid兼顾灵活性和可扩展性,适合不同规模项目,但社区及资源相对较少。选择框架应考虑项目需求和开发者偏好。
|
6天前
|
API 数据库 数据安全/隐私保护
Flask框架在Python面试中的应用与实战
【4月更文挑战第18天】Django REST framework (DRF) 是用于构建Web API的强力工具,尤其适合Django应用。本文深入讨论DRF面试常见问题,包括视图、序列化、路由、权限控制、分页过滤排序及错误处理。同时,强调了易错点如序列化器验证、权限认证配置、API版本管理、性能优化和响应格式统一,并提供实战代码示例。了解这些知识点有助于在Python面试中展现优秀的Web服务开发能力。
22 1
|
6天前
|
SQL 中间件 API
Flask框架在Python面试中的应用与实战
【4月更文挑战第18天】**Flask是Python的轻量级Web框架,以其简洁API和强大扩展性受欢迎。本文深入探讨了面试中关于Flask的常见问题,包括路由、Jinja2模板、数据库操作、中间件和错误处理。同时,提到了易错点,如路由冲突、模板安全、SQL注入,以及请求上下文管理。通过实例代码展示了如何创建和管理数据库、使用表单以及处理请求。掌握这些知识将有助于在面试中展现Flask技能。**
12 1
Flask框架在Python面试中的应用与实战
|
9天前
|
JSON 数据格式 Python
如何在Flask框架中定义路由和处理请求?
【4月更文挑战第18天】在Flask框架中,创建应用实例、定义路由和处理请求涉及5个步骤:1) 导入Flask并实例化应用;2) 使用`app.route()`装饰器定义路由,指定URL和HTTP方法;3) 编写视图函数处理请求逻辑;4) 视图函数返回响应内容,Flask会自动转换格式;5) 用`app.run()`启动服务器。
21 3
|
11天前
|
监控 安全 数据库
Flask应用部署指南:从开发到生产环境
【4月更文挑战第16天】本文是Flask应用从开发到生产的部署指南,涵盖开发环境准备、应用开发、部署方案选择、生产环境配置、应用部署、监控与维护。确保安装Python、Flask及依赖库,使用文本编辑器或IDE编写代码,关注应用安全与性能。选择WSGI服务器、Docker或云服务平台部署,配置生产环境,确保安全性,然后部署应用并进行监控维护,定期更新修复问题,保证应用稳定运行。
|
12天前
|
前端开发 数据挖掘 API
使用Python中的Flask框架进行Web应用开发
【4月更文挑战第15天】在Python的Web开发领域,Flask是一个备受欢迎的轻量级Web框架。它简洁、灵活且易于扩展,使得开发者能够快速地构建出高质量的Web应用。本文将深入探讨Flask框架的核心特性、使用方法以及在实际开发中的应用。
|
1月前
|
XML JSON API
通过Flask框架创建灵活的、可扩展的Web Restful API服务
通过Flask框架创建灵活的、可扩展的Web Restful API服务
|
1月前
|
开发框架 API 数据库
盘点Python网页开发轻量级框架Flask知识
盘点Python网页开发轻量级框架Flask知识
41 0
|
1月前
|
缓存 监控 API
Python Web框架FastAPI——一个比Flask和Tornada更高性能的API框架
Python Web框架FastAPI——一个比Flask和Tornada更高性能的API框架
58 0
|
程序员 数据库连接 Python
Flask 请求钩子
Flask 请求钩子