类 Flask 框架请求封装| 学习笔记

简介: 快速学习类 Flask 框架请求封装

开发者学堂课程【Python Web 开发基础类 Flask 框架请求封装】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址https://developer.aliyun.com/learning/course/554/detail/7638


类 Flask 框架请求封装


WSGI

图片1.png

WSGI 是一套协议它主要规定了 WSGI Server 与 WSGI App 之间是如何调用的,它规范了这个调用接口,那我们刚才已经有所了解了,所以说我们再回到说浏览器,发起的请求当然很多,浏览器不止一个,这边其实有很多 HTTP 请求,也就是说这边可能有很多 tcp 连接。  

那不管怎么说,对我们来说,从应用层角度来讲的话,它全部都是 HTTP 协议的这样一个请求,这个请求被 WSGI 获取到之后,就会对这个请求进行解析,解析之后将这些信息重新封装到一个字典中,这个字典就是 environment,这个字典把它所请求的这些数据装在一个环境数据的字典中,提供给大家使用。这个字典我们有的时候其实习惯了称为  request,也就是它的请求,请求数据,那这个信息我们拿到之后我,这个请求就得转发给你的这个 app,由 app 对这个请求进行处理,那往往会生成一些数据,这些数据最终要返回到浏览器端,但是必须按照 WSGI 的要求来做。

WSGI 在调用你的 app 的时候,会传入两个参数,第一个参数 environment,第二个参数 start response。这两样东西第一个是个字典,第二个呢是一个函数,这个函数拿到之后,在那个函数在 return 或者在向外提交你那个数据的时候,请你给他返回正文之前,请你调用他传进来这个 stata race boss ,这个函数里面一般要传3个信息,但是一般情况下你传2个就够了。

第一个 stater ,也就是说传入的状态码和他的描述第二个是 race boss ,也就是你要响应的头,这往往又是个字典或跟字典相当的,这个二元组组成集合往往都是这样子的。

有的时候也记不清了因为我们慢慢就不用太注重,所以我们想办法把它封装起来。

那这时,我们要处理东西,不管怎么样先调它,调用完之后把你组织好的正文内容放到一个可迭代对象里面去,然后 return 出去,别人要拿到你这个可迭代对象之后,要迭代的,迭代之后要把你这些每一个元素都通过 stp 封装,然后返回回去的,但是你返回的每一个这个封装你你这每一个元素我都要替你封装。

这些就是 WSGI 为我们提供的一套协议,那我们一般来讲遵守这套协议就可以开发了,遵守这套协议是 Python 为我们提供了一个参考的库,真要用的话一般来讲要使用 flask 这样的框架,那我们在学习的时候肯定会有很多障碍,所以我们必须先学 WSGI,以及我们看看他究竟是怎样处理数据的,因为他们代码量太大了,你一时半会都了解不了他到底是怎么处理数据的,很多层次数据在一个流程中不断的跑,跑到这个调用了,又被那个调用了,所以你看不清楚,所以我们就必须来自己写一个。

WSGI 主要规定了服务器端和应用程序间的接口。  

WSGI 服务器——wsgiref  

wsgiref 这个一个 WSGI 参考实现库  

wsgiref.simple_server 模块实现一个简单的 WSGI HTTP 服务器.  

wsgiref.simple_server.make_server(host, port, app, server_class=WSGIServer,  

handler_class=WSGIRequestHandler)启动一个 WSGI 服务器

wsgiref.simple_server.demo_app(environ, start_response)]一个函数,小巧完整的 WSGI 的应用程序的实现  

#返回文本例子  

from wsgiref.simple_server import make_server, demo_app  

ip ='127.0.0.1'  

port = 9999  

server = make_server(ip, port, demo_app)# demo_app 应用程序,可调用  

server.serve_forever()# server.handle_request()执行—次  

WSGI 服务器作用  

监听 HTTP 服务端口(TCPServer,默认端口80)

接收浏览器端的 HTTP 请求并解析封装成 environ 环境数据  

负责调用应用程序,将 environ 和 start_response 方法传入  

将应用程序响应的正文封装成HTTP响应报文返回浏览器端  

WSGI APP 应用程序端  

1、应用程序应该是一个可调用对象  

Python 中应该是函数、类、实现了_call_方法的类的实例  

2、这个可调用对象应该接收两个参数

# 1 函数实现  

def application(environ, start_response): pass  

# 2 类实现  

class Application: def _init_(self, environ, start_response): pass  

# 3 类实现  

class Application: def _call_(self, environ, start_response): pass  

3、以上的可调用对象实现,都必须返回一个可迭代对象

#函数实现  

def application(environ, start_response):  

return [res_str]  

#类实现  

class Application:  

def _init_(self, environ, start_response):  

pass  

def _iter_(self):#实现此方法,对象即可迭代  

yield res_str  

#类实现  

class Application:  

def _call_(self, environ, start_response):  

return[res_str]

environ和start_response 这两个参数名可以是任何合法名,但是一般默认都是这2个名字。应用程序端还有些其他的规定,暂不用关心

environ  

environ 是包含 Http 请求信息的dict对象  

名称

含义

REQUEST_METHOD

请求方法,GET、POST等

PATH_INFO

URL中的路径部分

QUERY_STRING

查询字符串

SERVER_NAME, SERVER_PORT

服务器名、端口

HTTP_HOST

地址和端口

SERVER_PROTOCOL

协议

HTTP_USER_AGENT

UserAgent信息

start_response  

它是一个可调用对象。有3个参数,定义如下:  

start_response(status, response_headers, exc_info=None) status 是状态码,例如 200 0K

response_headers 是一个元素为二元组的列表,例如[(Content-Type,'text/plain;charset=utf-8')]  

exc_info 在错误处理的时候使用  

start_response 应该在返回可迭代对象之前调用,因为它返回的是 Response Header。返回的可迭代对象是  Response Body.  

服务器端  

服务器程序需要调用符合上述定义的可调用对象 APP,传入 environ、start_response ,APP 处理后,返回响应头和可迭代对象的正文,由服务器封装返回浏览器端。

#返回网页的例子  

from wsgiref.simple_server import make_server  

def application(environ, start_response):  

status ='200 OK'  

headers =[('Content-Type",'text/html;charset=utf-8')]  

start_response(status, headers)  

#返回可迭代对象  

html ='

马哥教育欢迎你

".encode("utf-8")  

return [html]  

ip ='127.0.0.1'  

port = 9999  

server = make_server(ip, port, application)

server.serve_forever()# server.handle_request()一次  

simple_server 只是参考用,不能用于生产。  

测试用命令

$ curl -I http://192.168.142.1:9999/xxx?id=5|  

$ecurl -x POST http://192.168.142.1:9999/yyy -d'{"x":2}'  

使用 HEAD 方法

指定方法,-d 传输数据  

到这里就完成了一个简单的 WEB 程序开发。  

WEB 服务器  

•本质上就是一个 TCP 服务器,监听在特定端口上  

•支持 HTTP 协议,能够将 HTTP 请求报文进行解析,能够把响应数据进行 HTTP协议的报文封装并返回浏览器 端.  

•实现了 WSGI 协议,该协议约定了和应用程序之间接口(参看 PEP333,https://www.python.org/dev/peps/p ep-0333/)  

APP应用程序

•遵从 WSG 协议  

•本身是一个可调用对象  

•调用 start_response,返回响应头部  

•返回包含正文的可迭代对象  

为了更好的理解 WSGI 框架的工作原理,现在开始动手自己写一个 WEB 框架。

类 Flask 框架实现  

从现在开始,我们将一步步完成一个WSGI的WEB框架,从而了解WEB框架的内部机制。  

WSGI 请求 environ 处理  

WSGI 服务器程序会帮我们处理 HTTP 请求报文,但是提供的 environ 还是一个用起来不方便的字典  

http://127.6.0.1:9999/python/index.htm1?id=1234&name=tom  

('SERVER_PROTOCOL','HTTP/1.1')  

('wsgi.url_scheme",'http')  

('HTTP_HOST','127.0.0.1:9999')  

('SERVER_PORT','9999')  

('REMOTE_ADDR','127.0.0.1')  

('REQUEST_METHOD','GET')  

('CONTENT_TYPE','text/plain') ('PATH_INFO",'/python/index.html')  

('QUERY_STRING','id=1234&name=tom') ('HTTP_USER_AGENT','Mozilla/5.θ(Windows NT 6.1) ApplewebKit/537.36 (KHTML, like Gecko) Maxthon/5.0 Chrome/55.0.2883.75 Safari/537.36')

QUERY_STRING 查询字符串的解析  

WSGI 服务器程序处理过 HTTP 报文后,返回一个字典,可以得到查询字符串('QUERY_STRING", 'id=12348name=tom')。这个键值对用起来不方便。

1、编程序解析  

# id=5&name=wayne  

qstr = environ.get('QUERY_STRING')  

print(qstr)  

if qstr:  

for pair in qstr.split('&'):  

k,_,v= pair.partition('=')  

print("k={}, v={}".format(k,v))  

# id=5&name=wayne  

querystr = environ.get('QUERY_STRING')  

if querystr:  

querydict ={k:v for k,_,v in map(lambda item: item.partition('='), querystr.split('&'))} print(querydict)

2、使用 cgi 模块  

# id=5&name=wayne  

qstr= environ.get('QUERY_STRING')  

print(qstr)  

print(parse_qs(qstr))  

#{'name":['wayne"],'id":['5']}  

可以看到使用这个库,可以解析查询字符串,请注意value是列表,为什么? 这是因为同一个key可以有多个值。  

cgi模块过期了,建议使用urllib

3、使用 urllib 库  

#http://127.0.0.1:9999/?id=5&name=wayne&age=&commek=1,a,c&age=19&age=28  

qstr = environ.get('QUERY_STRING')  

print(qstr)  

print(parse.parse_qs(qstr))#字典  

print(parse.parse_qs1(qstr))#二元组列表  

#运行结果  

id=5&name=wayne&age=&comment=1,a,c&age=19&age=20  

{'name":['wayne'],'age":['19','26'],'id':['5'],'comment':['1,a,c']}  

[('id','5'),('name','wayne'),('comment",‘1,a,c'),('age','19'),('age','20')]  

parse_qs函数,将同一个名称的多值,保存在字典中,使用了列表保存。  

comment=1,a,c 这不是多值,这是一个值。  

age 是多值。  

environ 的解析——webob库

环境数据有很多,都是存在字典中的,字典的存取方式没有对象的属性访问方便。  

使用第三方库 webob,可以把环境数据的解析、封装成对象。  

webob 简介  

Python 下,可以对 WSGI 请求进行解析,并提供对响应进行高级封装的库。  

$ pip install webob  

官网文档 docs.webod.org  

webob.Request 对象  

将环境参数解析并封装成 request 对象  

GET 方法,发送的数据是 URL 中 Query string,在 Request Header 中。 request.GET 就是一个字典 MultiDict,里面就封装着查询字符串。

POST 方法,“提交”的数据是放在 Request Body 里面,但是也可以同时使用 Query String. request.POST 可以获取 Request Body 中的数据,也是个字典 MultiDict。

不关心什么方法提交,只关心数据,可以使用 request.params,它里面是所有提交数据的封装,。

request = webob.Request(environ)  

print(request.headers)#类字典容器  

print(request.method)  

print(request.path)  

print(request.query_string)#查询字符串  

print(request.GET)# GET 方法的所有数据  

print(request.POST)# POST 方法的所有数据  

print('params ={}'.format(request.params))#所有数据,参数

MultiDict  

MultiDict 允许一个 key 存了好几个值。

from webob.multidict import MultiDict  

md = MultiDict()  

md.add(1,'magedu')  

md.add(1,'.com'】  

md.add('a', 1)  

md.add('a', 2)  

md.add('b','3')  

md['b']='4 for pair in  

md.items(): print(pair) print(md.getall(1)】  

#print(md.getone('a'))#只能有一个值  

print(md.get('a'))#返回一个值  

print(md.get('c'))#不会抛异常 KeyError,返回 None

相关文章
|
21天前
|
安全 数据库 C++
Python Web框架比较:Django vs Flask vs Pyramid
【4月更文挑战第9天】本文对比了Python三大Web框架Django、Flask和Pyramid。Django功能全面,适合快速开发,但学习曲线较陡;Flask轻量灵活,易于入门,但默认配置简单,需自行添加功能;Pyramid兼顾灵活性和可扩展性,适合不同规模项目,但社区及资源相对较少。选择框架应考虑项目需求和开发者偏好。
|
9天前
|
API 数据库 数据安全/隐私保护
Flask框架在Python面试中的应用与实战
【4月更文挑战第18天】Django REST framework (DRF) 是用于构建Web API的强力工具,尤其适合Django应用。本文深入讨论DRF面试常见问题,包括视图、序列化、路由、权限控制、分页过滤排序及错误处理。同时,强调了易错点如序列化器验证、权限认证配置、API版本管理、性能优化和响应格式统一,并提供实战代码示例。了解这些知识点有助于在Python面试中展现优秀的Web服务开发能力。
24 1
|
5天前
|
API 开发者 Python
Django和Flask框架的主要区别是什么?
Django与Flask是Python Web开发的两大框架,各有特色。Django遵循“约定优于配置”,提供全栈式解决方案,适合大型项目和快速开发,但定制性相对有限。Flask是微框架,核心简洁,注重灵活性和可扩展性,适用于小型项目、高度定制的复杂项目及API开发。选择框架应考虑项目需求、团队技能和开发者偏好。
13 1
|
5天前
|
网络架构 Python
在Flask中,如何定义路由并处理HTTP请求的不同方法(GET、POST等)?
【4月更文挑战第25天】在Flask中,使用`@app.route()`装饰器定义路由,如`/hello`,处理GET请求返回'Hello, World!'。通过添加`methods`参数,可处理不同HTTP方法,如POST请求。单一函数可处理多种方法,通过检查`request.method`区分。动态路由使用 `<variable_name>` 传递URL变量到视图函数。这些基础构成处理HTTP请求的Flask应用。
12 1
|
9天前
|
SQL 中间件 API
Flask框架在Python面试中的应用与实战
【4月更文挑战第18天】**Flask是Python的轻量级Web框架,以其简洁API和强大扩展性受欢迎。本文深入探讨了面试中关于Flask的常见问题,包括路由、Jinja2模板、数据库操作、中间件和错误处理。同时,提到了易错点,如路由冲突、模板安全、SQL注入,以及请求上下文管理。通过实例代码展示了如何创建和管理数据库、使用表单以及处理请求。掌握这些知识将有助于在面试中展现Flask技能。**
14 1
Flask框架在Python面试中的应用与实战
|
12天前
|
JSON 数据格式 Python
如何在Flask框架中定义路由和处理请求?
【4月更文挑战第18天】在Flask框架中,创建应用实例、定义路由和处理请求涉及5个步骤:1) 导入Flask并实例化应用;2) 使用`app.route()`装饰器定义路由,指定URL和HTTP方法;3) 编写视图函数处理请求逻辑;4) 视图函数返回响应内容,Flask会自动转换格式;5) 用`app.run()`启动服务器。
21 3
|
14天前
|
Python
编写自己的Flask扩展:扩展框架的无限可能
【4月更文挑战第16天】本文介绍了如何编写Flask扩展以增强其功能。Flask扩展用于添加框架未内置的高级特性。一个扩展通常包括初始化函数、上下文处理器、命令行工具、信号处理和辅助函数。文中通过一个简单的自定义日志记录扩展示例,展示了创建扩展的步骤。扩展类`CustomLogger`包含初始化、请求前记录日志和自定义日志函数。通过`init_custom_logger`函数在应用中注册扩展。最后,展示了如何在应用中使用该扩展记录日志。编写Flask扩展可实现复杂逻辑、定制命令和处理事件,从而打造功能丰富的Web应用。
|
15天前
|
前端开发 数据挖掘 API
使用Python中的Flask框架进行Web应用开发
【4月更文挑战第15天】在Python的Web开发领域,Flask是一个备受欢迎的轻量级Web框架。它简洁、灵活且易于扩展,使得开发者能够快速地构建出高质量的Web应用。本文将深入探讨Flask框架的核心特性、使用方法以及在实际开发中的应用。
|
1月前
|
XML JSON API
通过Flask框架创建灵活的、可扩展的Web Restful API服务
通过Flask框架创建灵活的、可扩展的Web Restful API服务
|
程序员 数据库连接 Python
Flask 请求钩子
Flask 请求钩子