- Python Falcon教程
- Python Falcon - 主页
- Python Falcon - 简介
- Python Falcon - 环境设置
- Python Falcon - WSGI 与 ASGI
- Python Falcon - Hello World(WSGI)
- Python Falcon - 女服务员
- Python Falcon - ASGI
- 蟒蛇Falcon - Uvicorn
- Python Falcon - API 测试工具
- 请求与响应
- Python Falcon - 资源类
- Python Falcon - 应用程序类
- Python Falcon - 路由
- Falcon - 后缀响应者
- Python Falcon - 检查模块
- Python Falcon - Jinja2 模板
- Python Falcon - cookie
- Python Falcon - 状态代码
- Python Falcon - 错误处理
- Python Falcon - 钩子
- Python Falcon - 中间件
- Python Falcon - CORS
- Python Falcon - Websocket
- Python Falcon - Sqlalchemy 模型
- Python Falcon - 测试
- Python Falcon - 部署
- Python Falcon 有用资源
- Python Falcon - 快速指南
- Python Falcon - 有用的资源
- Python Falcon - 讨论
Python Falcon - 快速指南
Python Falcon - 简介
Falcon是一个用于开发关键任务 REST API 和微服务的 Python 库。它支持 WSGI 和 ASGI 规范。Falcon框架由Kurt Griffiths于2013年1月开发。Falcon的最新版本是3.1.0,于2022年3月发布。
Falcon 是一个轻量级的 Web 开发框架。其极简设计允许开发人员根据需要选择最佳策略和第三方软件包。
Falcon - 重要特性
Falcon 是根据 Apache 2.0 许可证条款发布的。
Falcon 的一些重要特征包括 -
最新版本的 Falcon 支持 ASGI、WSGI 以及 WebSocket。
Falcon 为 asyncio 提供本机支持。
其稳定的接口确保向后兼容性
Falcon 遵循 REST 架构风格来构建 API。
基于类的 HTTP 资源构造。
高度优化、可扩展的代码库。
Falcon 通过请求和响应类提供对标头和正文的轻松访问
可用于 DRY 请求处理的中间件组件和挂钩。
惯用的 HTTP 错误响应和异常处理。
Falcon-设计理念
Falcon 最小化实例化对象的数量,以避免创建对象的开销,并减少内存使用。同一实例将用于服务该路由上传入的所有请求。
异常由资源响应者正确处理(例如on_get()、on_post()等方法)。Falcon 并没有尽力保护响应者代码免受自身侵害。高质量的 Falcon API 应满足以下要求 -
资源响应者将响应变量设置为合理的值。
您的代码经过充分测试,代码覆盖率很高。
每个响应程序中都提供了自定义错误处理程序来预测、检测和处理错误。
Falcon 框架是线程安全的。为每个传入的 HTTP 请求创建单独的新 Request 和 Response 对象。但是,附加到路由的每个资源类的单个实例在所有请求之间共享。中间件对象、挂钩和自定义错误处理程序也是共享的。因此,您的 WSGI 应用程序作为一个整体将是线程安全的。
从 3.0 版本开始,Falcon 支持asyncio。使用falcon.asgi.App类创建异步应用程序,并通过 ASGI 应用程序服务器(例如Uvicorn )为其提供服务。
Falcon 的异步版本支持 ASGI WebSocket协议。
Falcon - 与其他框架的比较
Python Web 框架主要分为两大类:全栈框架和微框架。
全栈框架带有内置功能和库。Django、Turbogears和Web2Py是全栈框架。
相比之下,微框架是简约的,只提供最低限度的功能;因此,开发人员可以自由选择官方或第三方扩展,并且仅包含他们需要的插件。Flask、Falcon、Pyramid 都属于微框架范畴。
我们根据以下参数将 Falcon 框架与不同框架进行比较 -
表现
与 Flask、pyramid 等微框架相比,Falcon 应用速度非常快。全栈框架通常很慢。
休息支持
Falcon 旨在成为 REST API 和微服务开发的首选框架。FastAPI 还鼓励 REST 开发。Flask 和 Django 没有内置的 REST 支持。但是,可以使用扩展来启用它。
模板化
Falcon 应用程序不应提供模板网页。它不与任何模板库捆绑在一起。但是,可以使用jinja2或Macho库。另一方面,Flask 内置了对jinja2的支持。Django 有自己的模板库。FastAPI 还可以处理任何选择的模板库。
数据库支持
Falcon 数据库支持不是内置的。可以使用 SQLAlchemy 模型与 MySQL、PostgreSQL、SQLite 等关系数据库进行交互。另一方面,Django 有自己的 ORM 框架,可以开箱即用。
Flask 应用程序还可以通过 Flask 扩展与数据库交互。TurboGears 的早期版本与 SQLObject ORM 库兼容。新版本与 SQLAlchemy 兼容。
灵活性
Falcon的应用非常灵活。它非常适合需要高度定制和性能调整的应用程序。FastAPI 和 Flask 的编码也很灵活,不会将用户限制在特定的项目或代码布局中。
安全
Falcon 没有内置支持来确保安全。Django 和 FastAPI 等其他框架确保了高度的安全性。Flask 还针对 CSRF 和 XSS 攻击等安全威胁提供出色的保护。
测试
Falcon 使用 unittest 和 Pytest 提供内置测试支持。Flask 和 Django 也支持单元测试。FastAPI 支持单元测试和星形测试功能。
Python Falcon - 环境设置
最新版本的 Falcon 需要 Python 3.5 或更高版本。安装 Falcon 最简单也是推荐的方法是使用 PIP 安装程序,最好是在虚拟环境中。
可以通过运行以下命令安装最新的稳定版本 -
pip3 install falcon
要验证安装是否已成功执行,请导入库并检查其版本。
>>> import falcon >>>falcon.__version__ '3.1.0'
要安装最新的测试版,应使用以下命令 -
pip3 install --pre falcon
从早期版本开始,Falcon就支持WSGI。Falcon 应用程序可以在 Python 标准库模块wsgiref中内置 WSGI 服务器的帮助下运行。但是,它不适合生产环境,因为生产环境需要 WSGI 服务器,例如gunicorn、waitress 或uwsgi。
对于 Windows 上的 Falcon,可以使用Waitress,这是一种生产质量的纯 Python WSGI 服务器。像往常一样,使用 pip 安装程序安装它。
pip3 install waitress
Gunicorn服务器无法安装在 Windows 上。但是,它可以在Windows 10 上的Windows 子系统 Linux ( WSL ) 环境中使用。要在 Linux、WSL 或 Docker 容器内使用 Gunicorn,请使用
pip3 install gunicorn
如果要运行异步 Falcon 应用程序,则需要符合 ASGI 的应用程序服务器。Uvicorn 服务器可以在 Windows 和 Linux 系统上使用。
pip3 install uvicorn
Python Falcon - WSGI 与 ASGI
Web 服务器网关接口 (WSGI)
一些最流行的 Python Web 框架实现了 WSGI(代表Web 服务器网关接口)。WSGI本质上是一组Web服务器和Web应用程序之间通用接口的规范,由Web服务器软件实现,用于处理来自基于Python的Web应用程序的请求。WSGI 规范于 2003 年首次引入 (PEP 333),并于 2010 年更新 (PEP 3333)。
服务器通过传递以下参数来调用 WSGI 应用程序对象 -
environ - 一个 Python dict对象,类似于 CGI 环境变量和某些 WSGI 特定变量。
start_response - 应用程序使用的回调函数,用于返回其响应以及标头和状态代码。
该对象可以是 Python 中的任何可调用对象,例如函数、方法、类或其具有可用__call__()方法的实例。该应用程序对象必须返回一个由单字节字符串组成的迭代器。
def application (environ, start_response): ... ... return [("Hello World!".encode("utf-8")]
然而,启用 WSGI 的服务器在操作上是同步的,因此应用程序的效率不高。Python 在 3.4 版本中引入了asyncio模块作为标准库的一部分,开始支持异步编程。
asyncio模块提供了在 Python 应用程序中合并并发编程风格(通常称为协作多任务)的能力。在这种方法中,操作系统不会阻碍不同进程之间的上下文切换。相反,一个进程会定期让出以容纳其他进程,以便许多应用程序可以同时运行。
在Python的3.5版本中,添加了async和await这两个关键字。使用 async 关键字定义的 Python 函数将成为协程,因此无法像普通函数一样运行。相反,我们需要使用asyncio.run (coroutine)来调用它。可以通过await关键字暂停一个协程的执行,直到另一个协程完成。
import asyncio async def main(): print('hello') await asyncio.sleep(5) print('world') asyncio.run(main())
异步服务器网关接口(ASGI)
ASGI 代表异步服务器网关接口(根据其官方文档,它是 WSGI 的精神继承者),它为 Python Web 服务器、应用程序和框架添加了异步功能。
ASGI 应用程序是一个异步可调用对象(用户定义的函数或具有__call__()方法的类的对象)。它需要三个参数,如下 -
范围-包含特定连接详细信息的字典
Send - 异步可调用,通过它可以将事件消息发送到客户端
接收- 另一个异步可调用。应用程序可以接收来自客户端的事件消息。
以下是由异步函数表示的简单 ASGI 应用程序的原型 -
async def app(scope, receive, send): assert scope['type'] == 'http' await send({ 'type': 'http.response.start', 'status': 200, 'headers': [ [b'content-type', b'text/plain'], ], }) await send({ 'type': 'http.response.body', 'body': b'Hello, world!', })
Python Falcon - Hello World(WSGI)
要创建一个简单的 Hello World Falcon 应用程序,请首先导入库并声明 App 对象的实例。
import falcon app = falcon.App()
Falcon遵循REST架构风格。声明一个资源类,其中包含一个或多个表示标准 HTTP 动词的方法。以下HelloResource类包含on_get()方法,预计在服务器收到GET请求时调用该方法。该方法返回 Hello World 响应。
class HelloResource: def on_get(self, req, resp): """Handles GET requests""" resp.status = falcon.HTTP_200 resp.content_type = falcon.MEDIA_TEXT resp.text = ( 'Hello World' )
要调用此方法,我们需要将其注册到路由或 URL。Falcon 应用程序对象通过add_rule方法将处理程序方法分配给相应的 URL 来处理传入的请求。
hello = HelloResource() app.add_route('/hello', hello)
Falcon 应用程序对象只不过是一个 WSGI 应用程序。我们可以使用Python标准库的wsgiref模块中内置的WSGI服务器。
from wsgiref.simple_server import make_server if __name__ == '__main__': with make_server('', 8000, app) as httpd: print('Serving on port 8000...') # Serve until process is killed httpd.serve_forever()
例子
让我们把所有这些代码片段放在hellofalcon.py中
from wsgiref.simple_server import make_server import falcon app = falcon.App() class HelloResource: def on_get(self, req, resp): """Handles GET requests""" resp.status = falcon.HTTP_200 resp.content_type = falcon.MEDIA_TEXT resp.text = ( 'Hello World' ) hello = HelloResource() app.add_route('/hello', hello) if __name__ == '__main__': with make_server('', 8000, app) as httpd: print('Serving on port 8000...') # Serve until process is killed httpd.serve_forever()
从命令提示符运行此代码。
(falconenv) E:\falconenv>python hellofalcon.py Serving on port 8000...
输出
在另一个终端中,运行 Curl 命令,如下所示 -
C:\Users\user>curl localhost:8000/hello Hello World
您还可以打开浏览器窗口并输入上述 URL 来获取“Hello World”响应。
Python Falcon - 女服务员
开发服务器不建议用于生产环境。开发服务器效率不高、不稳定或安全。
Waitress 是一个生产质量的纯 Python WSGI 服务器,具有非常可接受的性能。除了 Python 标准库中的依赖项之外,它没有任何依赖项。它在 Unix 和 Windows 上的 CPython 上运行。
确保工作环境中已安装Waitress服务器。该库包含服务类,其对象负责服务传入的请求。serve类的构造函数需要三个参数。
serve (app, host, port)
falcon应用程序对象是app参数。主机和端口默认值为 localhost 8080。监听参数是一个由主机:端口参数组合而成的字符串,默认为“0.0.0.0:8080”
例子
在hellofalcon.py代码中,我们导入serve类而不是simple_server并实例化其对象,如下所示 -
from waitress import serve import falcon class HelloResource: def on_get(self, req, resp): """Handles GET requests""" resp.status = falcon.HTTP_200 resp.content_type = falcon.MEDIA_TEXT resp.text = ( 'Hello World' ) app = falcon.App() hello = HelloResource() app.add_route('/hello', hello) if __name__ == '__main__': serve(app, host='0.0.0.0', port=8000)
执行hellofalcon.py ,像之前一样在浏览器中访问http://localhost:8000/hellolink 。请注意,主机 0.0.0.0 使本地主机公开可见。
Waitress 服务器也可以从命令行启动,如下所示 -
waitress-serve --port=8000 hellofalcon:app
Python Falcon - ASGI
ASGI 代表异步服务器网关接口(根据其官方文档,它是 WSGI 的精神继承者),它为 Python Web 服务器、应用程序和框架添加了异步功能。
为了运行异步 Web 应用程序,我们需要一个 ASGI 应用程序服务器。流行的选择包括 -
- 独角兽
- 芫
- 超级玉米
在本教程中,我们将使用Uvicorn服务器作为异步示例。
你好世界-ASGI
Falcon 的 ASGI 相关功能可在 falcon.asgi 模块中找到。因此,我们需要在一开始就导入它。
import falcon import falcon.asgi
虽然资源类与前面的示例相同,但 on_get() 方法必须使用 async 关键字声明。我们必须获取 Falson 的 ASGI 应用程序的实例。
app = falcon.asgi.App()
例子
因此,ASGI 的 hellofalcon.py 将如下 -
import falcon import falcon.asgi class HelloResource: async def on_get(self, req, resp): """Handles GET requests""" resp.status = falcon.HTTP_200 resp.content_type = falcon.MEDIA_TEXT resp.text = ( 'Hello World' ) app = falcon.asgi.App() hello = HelloResource() app.add_route('/hello', hello)
要运行该应用程序,请从命令行启动 Uvicorn 服务器,如下所示 -
uvicorn hellofalcon:app –reload
输出
打开浏览器并访问http://localhost:/8000/hello。您将在浏览器窗口中看到响应。
蟒蛇Falcon - Uvicorn
Uvicorn 使用uvloop和httptools库。它还提供对 HTTP/2 和 WebSockets 的支持,这是 WSGI 无法处理的。uvloop类似于内置的asyncio事件循环。httptools库处理 http 协议。
Falcon 的 ASGI 兼容应用程序使用以下命令在 Uvicorn 服务器上启动 -
Uvicorn hellofalcon:app – reload
--reload选项启用调试模式,这样 app.py 中的任何更改都会自动反映,并且客户端浏览器上的显示会自动刷新。此外,可以使用以下命令行选项 -
--主机文本 | 将套接字绑定到该主机。[默认127.0.0.1] |
--端口整数 | 将套接字绑定到此端口。[默认8000] |
--uds 文本 | 绑定到 UNIX 域套接字。 |
--fd 整数 | 从此文件描述符绑定到套接字。 |
--重新加载 | 启用自动重新加载。 |
--reload-dir 路径 | 显式设置重新加载目录,默认当前工作目录。 |
--reload-包含文本 | 观看时包含文件。默认情况下包含“* .py ” |
--reload-排除文本 | 监视文件时排除。 |
--重新加载延迟浮动 | 上一次检查和下一次检查之间的延迟默认 0.25 |
--loop [自动|异步|uvloop] | 事件循环实现。[默认自动] |
--http [自动|h11|httptools] | HTTP协议的实现。[默认自动] |
--接口自动|asgi|wsgi | 选择应用程序界面。[默认自动] |
--env-文件路径 | 环境配置文件。 |
--log-config 路径 | 记录配置文件。支持的格式.ini、.json、.yaml。 |
- 版本 | 显示 Uvicorn 版本并退出。 |
--app-dir 文本 | 在指定目录默认当前目录下查找APP |
- 帮助 | 显示此消息并退出。 |
Uvicorn 服务器也可以从程序内部启动,而不是通过上面的命令行。为此,导入uvicorn模块并调用uvicorn.run()方法,如下所示 -
import uvicorn if __name__ == "__main__": uvicorn.run("hellofalcon:app", host="0.0.0.0", port=8000, reload=True)
相应地更改 hellofalcon.py 代码,并从命令提示符执行相同的代码。结果可以通过curl命令或在浏览器中验证,如前所述。
Python Falcon - API 测试工具
Falcon 是一个适合开发 API 的简约框架。API 是两个应用程序之间的接口。API开发者在将其发布到生产环境中使用之前,需要对其功能、可靠性、稳定性、可扩展性、性能等进行测试。
有多种 API 测试工具可用于此目的。在本节中,我们将学习如何使用命令行工具Curl和HTTPie以及名为Postman 的GUI 工具。
卷曲
cURL 是一个开源项目,提供 libcurl 库和一个名为curl 的命令行工具,可以使用各种协议传输数据。支持包括 HTTP 在内的 20 多种协议。首字母缩略词 cURL 代表客户端 URL。从命令行使用 Curl 的语法是 -
curl [options] [URL1, URL2,..]
URL 参数由依赖于协议的一个或多个 URL 字符串组成。可以使用各种选项自定义 Curl 命令。一些重要的命令行选项如下 -
– X:提及请求方法。默认情况下,Curl 假定 GET 为请求方法。要发送 POST、PUT 或 DELTETE 请求,必须使用此选项。例如 -
Curl –X DELETE http://localhost:8000/student/1
-H:该选项用于在请求中添加标头。例如 -
Curl –H "Content-Type: application/json" -X GET http://localhost:8000/students
-i:当命令行中包含该选项时,将显示所有响应头。例如 -
Curl –I –X DELETE http://localhost:8000/student/2
-d:要在HTTP请求中包含数据进行处理,我们必须使用此选项,特别是当需要POST或PUT请求时。
Curl –H "Content-Type: application/json" -X PUT -d "{"""marks""":"""50"""}" http://localhost:8000/students/3
HTTPie
HTTPie 是一个用 Python 编写的命令行工具。据说它是“人类的类似 cURL 的工具”。它支持表单和文件上传,并生成格式良好的彩色终端输出。与 Curl 相比,其富有表现力和直观的语法使其更易于使用。
例子
GET 请求- http GET localhost:8000/students
POST 请求- http POST localhost:8000/students id=4 name="aaa"%=50
PUT 请求- http PUT localhost:8000/students/2 id=3 name="Mathews"%=55
DEETE 请求- http DELETE localhost:8000/students/2
邮差
Postman是一个非常流行的API测试工具。它是一个 GUI 应用程序,与 Curl 和 HTTPie 不同。它以浏览器插件和桌面应用程序的形式提供。由于浏览器插件不接受基于 localhost 的 API 请求,因此我们需要从https://www.postman.com/downloads 下载桌面版本。
完成基于向导的安装后,启动 Postman 应用程序并创建新请求。
下拉列表显示可供选择的各种 HTTP 请求类型。
在请求 URL 字段中输入http://localhost:8000/hello 。右侧的响应窗格显示结果。
稍后我们在 SQLite 数据库上测试 Falcon API 的 CRUD 操作时将使用相应的请求类型。
Python Falcon - 请求和响应
HTTP 协议规定,客户端向服务器发送 HTTP 请求,服务器应用特定的业务逻辑并制定响应,该响应被重定向到客户端。两者之间同步传输时,Python框架使用WSGI标准,而异步传输则遵循ASGI标准。Falcon支持两者。
WSGI/ASGI 服务器在上下文数据中提供请求和响应对象。这些对象被响应者、钩子、中间件等用作参数。对于 WSGI 应用程序,将处理falcon.Request类的实例。在 ASGI 应用程序中,它代表falcon.asgi.Request类。虽然不同,但这两个类都被设计为具有相似的属性和方法,以尽量减少混乱并更容易移植。
要求
Request 对象代表 HTTP 请求。由于它是由服务器提供的,因此该对象并不意味着由响应程序方法直接实例化。该对象提供了以下属性和方法,可在响应程序、挂钩和中间件方法中使用 -
method - 请求的 HTTP 方法(例如“GET”、“POST”等)
host - 主机请求标头字段
port - 用于请求的端口。返回给定模式的默认值(HTTP 为 80,HTTPS 为 443)
uri - 请求的完全限定 URI。
path - 请求 URI 的路径部分(不包括查询字符串)。
query_string - 请求 URI 的查询字符串部分,前面不带“?” 特点。
cookies - 名称/值 cookie 对的字典。
content_type - Content-Type 标头的值,如果标头丢失则为 None 。
Stream - 用于读取请求正文的类似文件的输入对象(如果有)。该对象提供对服务器数据流的直接访问并且是不可查找的。
bounded_stream - 流周围的类似文件的包装器
headers - 请求中的原始 HTTP 标头
params - 请求查询参数名称与其值的映射。
get_cookie_values(name) - 返回指定 cookie 的 Cookie 标头中提供的所有值。cookies 属性的别名。
get_media() - 返回请求流的反序列化形式。类似于媒体财产。
get_param(name) - 以字符串形式返回查询字符串参数的原始值。如果发布了带有application/x-wwwform-urlencoded媒体类型的 HTML 表单,Falcon 可以自动解析请求正文中的参数并将它们合并到查询字符串参数中。要启用此功能,请通过App.req_options将auto_parse_form_urlencoded设置为 True 。
回复
Response 对象表示服务器对客户端的 HTTP 响应。与 Request 对象一样,Response 对象也不应该由响应者直接实例化。
响应者、钩子函数或中间件方法通过访问以下属性和方法来操纵该对象 -
status - HTTP 状态代码,例如“200 OK”。这可以设置为http.HTTPStatus的成员、HTTP 状态行字符串或字节字符串或 int。Falcon 为常见状态代码提供了许多常量,以 HTTP_ 前缀开头,如 - falcon.HTTP_204。
media - 通过falcon.RequestOptions配置的媒体处理程序支持的可序列化对象。
text - 表示响应内容的字符串。
body - 已弃用的文本别名。
data - 表示响应内容的字节字符串。
流- 表示响应内容的类似文件的对象。
content_length - 设置内容长度标头。当未设置文本或数据属性时,它会手动设置内容长度。
content_type - 设置内容类型标头。Falcon 针对常见媒体类型的预定义常量包括 falcon.MEDIA_JSON、falcon.MEDIA_MSGPACK、falcon.MEDIA_YAML、falcon.MEDIA_XML、falcon.MEDIA_HTML、falcon.MEDIA_JS、falcon.MEDIA_TEXT、falcon.MEDIA_JPEG、falcon.MEDIA_PNG 和 falcon.MEDIA_GIF。
append_header (name, value) - 设置或附加此响应的标头。用于设置cookie。
delete_header (name) - 删除之前为此响应设置的标头。
get_header (name) - 检索给定标头的原始字符串值。
set_cookie (name, value) - 设置响应 cookie。可以多次调用此方法以将一个或多个 cookie 添加到响应中。
set_header (name, value) - 将此响应的标头设置为给定值。
set_stream (stream, content_length) - 设置流和content_length。
unset_cookie (name, domain=None, path=None) - 取消设置响应中的 cookie。此方法清除 cookie 的内容,并指示用户代理立即使自己的 cookie 副本失效。
Python Falcon - 资源类
Falcon 的设计借鉴了 REST 架构风格的几个关键概念。REST 代表关系状态传输。REST 定义了 Web 应用程序架构的Behave方式。
REST 是一种基于资源的架构。在这里,REST 服务器托管的所有内容(无论是文件、图像还是数据库表中的行)都被视为资源,可能有多种表示形式。REST API 提供对这些资源的受控访问,以便客户端可以检索和修改它们。
服务器的资源应该只有一个统一资源标识符 (URI)。它仅标识资源;它没有指定对该资源采取什么操作。相反,用户从一组标准方法中进行选择。用于对资源进行操作的 HTTP 动词或方法。POST、GET、PUT 和 DELETE 方法分别执行 CREATE、READ、UPDATE 和 DELETE 操作。
Falcon 使用普通的 Python 类来表示资源。这样的类充当应用程序中的控制器。它将传入请求转换为一个或多个内部操作,然后根据这些操作的结果编写返回给客户端的响应。
每个资源类都定义了各种“响应程序”方法,一种对应于资源允许的每种 HTTP 方法。响应程序名称以“on_”开头,并根据它们处理的 HTTP 方法进行命名,如on_get()、on_post()、on_put()等。
在上面使用的hellofalcon.py示例代码中,HelloResource(资源类)有一个on_get()响应器方法。响应者必须始终定义至少两个参数来接收请求和响应对象。
import falcon class HelloResource: def on_get(self, req, resp): """Handles GET requests""" resp.status = falcon.HTTP_200 resp.content_type = falcon.MEDIA_TEXT resp.text = ( 'Hello World' )
对于ASGI应用程序,响应者必须是协程函数,即必须使用async关键字定义。
class HelloResource: async def on_get(self, req, resp): """Handles GET requests""" resp.status = falcon.HTTP_200 resp.content_type = falcon.MEDIA_TEXT resp.text = ( 'Hello World' )
Request对象表示传入的 HTTP 请求。可以通过此对象访问请求标头、查询字符串参数以及与请求关联的其他元数据。
Response 对象表示应用程序对请求的 HTTP 响应。该对象的属性和方法设置状态、标头和正文数据。它还公开了一个类似字典的上下文属性,用于将任意数据传递给钩子和其他中间件方法。
请注意,上面示例中的HelloResource只是一个普通的 Python 类。它可以有任何名称;但是,约定将其命名为xxxResource。
Python Falcon - 应用程序类
此类是基于 Falcon 的 WSGI 应用程序的主要入口点。此类的实例提供可调用的 WSGI 接口和路由引擎。
import falcon app = falcon.App()
此类的__init __()构造函数采用以下关键字参数 -
media_type - 初始化 RequestOptions 和 ResponseOptions 时使用的媒体类型。Falcon 允许轻松且可定制的互联网媒体类型处理。默认情况下,Falcon 仅启用 JSON 和 HTML(URL 编码和多部分)表单的处理程序。
falcon.MEDIA_JSON
falcon.MEDIA_MSGPACK
Falcon.MEDIA_MULTIPART
falcon.MEDIA_URLENCODED
falcon.MEDIA_YAML
falcon.MEDIA_XML
Falcon.MEDIA_HTML
Falcon.MEDIA_JS
Falcon.MEDIA_TEXT
Falcon.MEDIA_JPEG
Falcon.MEDIA_PNG
Falcon.MEDIA_GIF
request_type - 此参数的默认值是falcon.Request类。
response_type - 此参数的默认值为falcon.Response类。
Falcon 支持的其他媒体类型由以下常量表示 -
为了使App对象可调用,它的类有一个__call__()方法。
__call__(self, env, start_response)
这是一个 WSGI 应用程序方法。WSGI 开发服务器或其他生产服务器(Waitress/Uvicorn)使用此对象来启动服务器实例并侦听来自客户端的请求。
App 类还定义了 add_route() 方法。
add_route(self, uri_template, resource)
此方法有助于将 URI 路径与资源类的对象关联起来。传入请求将根据一组 URI 模板路由到资源。如果路径与给定路由的模板匹配,则请求将被传递到关联的资源进行处理。根据请求方法,调用相应的响应程序方法。
例子
让我们将on_post()响应程序方法添加到HelloResource类并测试 GET 和 POST 请求的端点。
from waitress import serve import falcon import json class HelloResource: def on_get(self, req, resp): resp.status = falcon.HTTP_200 resp.content_type = falcon.MEDIA_TEXT resp.text = ( 'Hello World' ) def on_post(self, req, resp): data=req.media nm=data['name'] resp.status = falcon.HTTP_200 resp.content_type = falcon.MEDIA_TEXT resp.text = ( 'Hello '+nm ) app = falcon.App() hello = HelloResource() app.add_route('/hello', hello) if __name__ == '__main__': serve(app, host='0.0.0.0', port=8000)
输出
使用 Waitress 服务器运行应用程序并使用 Curl 检查响应。要响应 GET 请求,请使用以下命令 -
C:\Users\User>curl localhost:8000/hello Hello World
我们通过 POST 方法将一些数据发送到 /hello URL,如下所示 -
C:\Users\User>curl -i -H "Content-Type:application/json" -X POST -d "{"""name""":"""John"""}" http://localhost:8000/hello HTTP/1.1 200 OK Content-Length: 10 Content-Type: text/plain; charset=utf-8 Date: Sun, 17 Apr 2022 07:06:20 GMT Server: waitress Hello John
要添加到静态文件目录的路由,Falcon 有add_static_route()方法。
add_static_route(self, prefix, directory, downloadable=False, fallback_filename=None)
prefix 参数是与该路由匹配的路径前缀。目录参数是提供文件的源目录。如果您想在响应中包含 ContentDisposition 标头,则可下载参数设置为 True。Fallback_filename默认为 None,但可以在找不到请求的文件时指定。
add_error_handler ()方法用于注册一种或多种异常类型的处理程序。
add_error_handler(self, exception, handler=None)
ASGI 可调用 App 类拥有相同的方法。它在 falcon.asgi 模块中定义。
import falcon.asgi app=falcon.asgi.App()
请注意,ASGI 应用程序中资源类的响应者必须是协程(使用async关键字定义)而不是普通方法。
class HelloResource: async def on_get(self, req, resp): """Handles GET requests""" resp.status = falcon.HTTP_200 resp.content_type = falcon.MEDIA_TEXT resp.text = ( 'Hello World' )
Python Falcon - 路由
Falcon采用RESTful架构风格。因此它使用基于资源的路由。资源类负责处理响应者的 HTTP 方法,这些方法本质上是名称以 on_ 开头并以小写 HTTP 方法名称结尾的类方法(例如 on_get()、on_patch()、on_delete()等) .)。Falcon 应用程序对象的add_route ()方法将其路由器与资源类的实例关联起来。
在上面使用的 Hellofalcon.py 示例中,当客户端分别通过 GET 和 POST 方法请求/hello路由时,将调用on_get()和on_post()响应程序。
如果没有路由与请求匹配,则会引发HTTPRouteNotFound实例。另一方面,如果路由匹配但资源未实现所请求的 HTTP 方法的响应程序,则默认响应程序将引发HTTPMethodNotAllowed的实例。
现场转换器
Falcon 的路由机制允许 URL 将参数传递给响应者。URL 由三部分组成: 协议(例如http://或https://),后跟 IP 地址或主机名。URL 的第一个/主机名之后的剩余部分称为路径或端点。要传递的参数位于端点之后。
它充当资源标识符,例如唯一 ID 或主键。参数名称括在大括号中。除了请求和响应之外,路径参数的值还将转到响应者方法中定义的参数。
在以下示例中,路由器将资源类对象与由端点后面的参数组成的 URL 相关联。
from waitress import serve import falcon import json class HelloResource: def on_get(self, req, resp, nm): """Handles GET requests""" resp.status = falcon.HTTP_200 resp.content_type = falcon.MEDIA_TEXT resp.text = ( 'Hello '+nm ) app = falcon.App() hello = HelloResource() app.add_route('/hello/{nm}', hello) if __name__ == '__main__': serve(app, host='0.0.0.0', port=8000)
我们可以看到on_get()响应者方法有一个额外的参数 nm 来接受从 URL 路由解析的数据。让我们使用HTTPie工具测试http://localhost:8000/hello/Priya。
>http GET localhost:8000/hello/Priya HTTP/1.1 200 OK Content-Length: 11 Content-Type: text/plain; charset=utf-8 Date: Mon, 18 Apr 2022 12:27:35 GMT Server: waitress Hello Priya
路径参数解析为的默认数据类型是str(即字符串)。然而,Falcon 的路由器引擎具有以下内置字段转换器,使用它们也可以将它们读入其他数据类型。
IntConverter - 此类在falcon.routing模块中定义。构造函数使用以下参数 -
IntConverter(num_digits=None, min=None, max=None)
num_digits - 该值必须具有给定的位数。
min - 参数的最小要求值
max - 参数的最大允许值。
在哪里,
例如,以下add_route()函数接受 1 到 100 之间的整数作为rollno。
app.add_route('/student/{rollno:int(1,1,100}', StudentResource())
UUIDConverter - falcon.routing 模块中的此类将 32 个十六进制数字的字符串转换为 UUID(通用唯一标识符)。
DateTimeConverter - 将参数字符串转换为日期时间变量。参数必须是strptime()函数识别的任何格式的字符串,默认为'%Y-%m-%dT%H:%M:%SZ'。
格式字符串使用以下格式代码 -
%A | 工作日缩写名称 | 周日、周一 |
%A | 工作日的完整名称 | 星期天星期一 |
%d | 以零填充小数表示的月份中的某一天 | 01, 02 |
%-d | 十进制数形式的月份中的某一天 | 1, 2.. |
%b | 月份名称缩写 | 一月、二月 |
%m | 月份作为补零十进制数 | 01, 02 |
%B | 完整的月份名称 | 一月二月 |
%-y | 没有世纪的年份作为十进制数 | 0, 99 |
%Y | 年份,世纪为十进制数 | 2000年、1999年 |
%H | 小时(24 小时制)作为补零十进制数 | 01, 23 |
%p | 区域设置的 AM 或 PM | 上午下午 |
%-M | 以十进制表示的分钟 | 1, 59 |
%-S | 第二位十进制数 | 1, 59 |
在以下示例中,add_route()函数将带有两个参数的 URL 与 Resource 对象相关联。第一个参数 nm 默认是一个字符串。第二个参数 Age 使用IntConverter。
from waitress import serve import falcon import json class HelloResource: def on_get(self, req, resp, nm,age): """Handles GET requests""" retvalue={"name":nm, "age":age} resp.body=json.dumps(retvalue) resp.status = falcon.HTTP_200 resp.content_type = falcon.MEDIA_JSON app = falcon.App() hello = HelloResource() app.add_route('/hello/{nm}/{age:int}', hello) if __name__ == '__main__': serve(app, host='0.0.0.0', port=8000)
请注意,on_get()响应程序使用路径参数来形成一个dict对象 – retvalue。然后将其 JSON 表示形式指定为响应正文的值并返回给客户端。如前所述,JSON 是 Falcon 响应对象的默认内容类型。
启动 Waitress 服务器并在HTTPie的帮助下检查 URL http://localhost:8000/hello/Priya/21的响应。
http GET localhost:8000/hello/Priya/21 HTTP/1.1 200 OK Content-Length: 28 Content-Type: application/json Date: Fri, 22 Apr 2022 14:22:47 GMT Server: waitress { "age": 21, "name": "Priya" }
您还可以在浏览器中检查响应,如下所示 -
Python Falcon - 带后缀的响应者
为了理解后缀响应者的概念和需求,让我们定义一个StudentResource类。它由一个on_get()响应程序组成,该响应程序将学生的dict对象列表转换为 JSON 并作为其响应返回。
我们还添加on_post()响应程序,该响应程序从传入请求中读取数据并在列表中添加一个新的dict对象。
import falcon import json from waitress import serve students = [ {"id": 1, "name": "Ravi", "percent": 75.50}, {"id": 2, "name": "Mona", "percent": 80.00}, {"id": 3, "name": "Mathews", "percent": 65.25}, ] class StudentResource: def on_get(self, req, resp): resp.text = json.dumps(students) resp.status = falcon.HTTP_OK resp.content_type = falcon.MEDIA_JSON def on_post(self, req, resp): student = json.load(req.bounded_stream) students.append(student) resp.text = "Student added successfully." resp.status = falcon.HTTP_OK resp.content_type = falcon.MEDIA_TEXT
使用Falcon 的 App 对象的add_route()函数,我们添加/students路由。
app = falcon.App() app.add_route("/students", StudentResource())
启动服务器后,我们可以从 HTTPie 命令行测试 GET 和 POST 请求 -
http GET localhost:8000/students HTTP/1.1 200 OK Content-Length: 187 Content-Type: application/json Date: Mon, 18 Apr 2022 06:21:02 GMT Server: waitress [ { "id": 1, "name": "Ravi", "percent": 75.5 }, { "id": 2, "name": "Mona", "percent": 80.0 }, { "id": 3, "name": "Mathews", "percent": 65.25 } ] http POST localhost:8000/students id=4 name="Prachi" percent=59.90 HTTP/1.1 200 OK Content-Length: 27 Content-Type: text/plain; charset=utf-8 Date: Mon, 18 Apr 2022 06:20:51 GMT Server: waitress Student added successfully.
再次调用on_get()确认添加新学生资源。
http GET localhost:8000/students HTTP/1.1 200 OK Content-Length: 187 Content-Type: application/json Date: Mon, 18 Apr 2022 06:21:02 GMT Server: waitress [ { "id": 1, "name": "Ravi", "percent": 75.5 }, { "id": 2, "name": "Mona", "percent": 80.0 }, { "id": 3, "name": "Mathews", "percent": 65.25 }, { "id": "4", "name": "Prachi", "percent": "59.90" } ]
在此阶段,我们希望在StudentResource类中有一个 GET 响应器方法,该方法从 URL 读取 id 参数并从列表中检索相应的dict对象。
换句话说,/student/{id} 格式的 URL 应该与资源类中的 GET 方法相关联。但显然,一个类不能有两个同名的方法。因此,我们定义在add_route()方法中使用后缀参数来区分on_get()响应者的两个定义。
通过指定suffix ='student' ,将带有 id 参数的路由添加到 Application 对象。
app.add_route("/students/{id:int}", StudentResource(), suffix='student')
现在,我们可以使用此后缀添加on_get()方法的另一个定义,以便该响应者的名称为on_get_student(),如下所示 -
def on_get_student(self, req, resp, id): resp.text = json.dumps(students[id-1]) resp.status = falcon.HTTP_OK resp.content_type = falcon.MEDIA_JSON
添加新路由和on_get_student()响应程序后启动Waitress服务器并测试此 URL,如下所示 -
http GET localhost:8000/students/2 HTTP/1.1 200 OK Content-Length: 42 Content-Type: application/json Date: Mon, 18 Apr 2022 06:21:05 GMTy Server: waitress { "id": 2, "name": "Mona", "percent": 80.0 }
请注意,当客户端使用适当的请求标头请求URL 路由/students/{id:int}时,也会调用on_put()响应程序(用于更新资源)和on_delete()响应程序(用于删除资源)。
我们已经添加了这条以学生为后缀的路线。因此,on_put_student()方法解析整型变量中的路径参数。将获取具有给定 id 的项目的 JSON 表示形式,并使用 PUT 请求中提供的数据进行更新。
def on_put_student(self, req, resp, id): student=students[id-1] data = json.load(req.bounded_stream) student.update(data) resp.text = json.dumps(student) resp.status = falcon.HTTP_OK resp.content_type = falcon.MEDIA_JSON
on_delete_student ()响应程序只是删除具有 DELETE 请求中指定的 id 的项目。返回剩余资源列表。
def on_delete_student(self, req, resp, id): students.pop(id-1) resp.text = json.dumps(students) resp.status = falcon.HTTP_OK resp.content_type = falcon.MEDIA_JSON
我们可以使用HTTPie命令测试 API 的 PUT 和 DELETE 操作-
http PUT localhost:8000/students/2 id=3 name="Mathews" percent=55 HTTP/1.1 200 OK Content-Length: 46 Content-Type: application/json Date: Sat, 18 Apr 2022 10:13:00 GMT Server: waitress { "id": "3", "name": "Mathews", "percent": "55" } http DELETE localhost:8000/students/2 HTTP/1.1 200 OK Content-Length: 92 Content-Type: application/json Date: Sat, 18 Apr 2022 10:18:00 GMT Server: waitress [ { "id": 1, "name": "Ravi", "percent": 75.5 }, { "id": 3, "name": "Mathews", "percent": 65.25 } ]
该 API ( studentapi.py )的完整代码如下 -
import falcon import json from waitress import serve students = [ {"id": 1, "name": "Ravi", "percent": 75.50}, {"id": 2, "name": "Mona", "percent": 80.00}, {"id": 3, "name": "Mathews", "percent": 65.25}, ] class StudentResource: def on_get(self, req, resp): resp.text = json.dumps(students) resp.status = falcon.HTTP_OK resp.content_type = falcon.MEDIA_JSON def on_post(self, req, resp): student = json.load(req.bounded_stream) students.append(student) resp.text = "Student added successfully." resp.status = falcon.HTTP_OK resp.content_type = falcon.MEDIA_TEXT def on_get_student(self, req, resp, id): resp.text = json.dumps(students[id-1]) resp.status = falcon.HTTP_OK resp.content_type = falcon.MEDIA_JSON def on_put_student(self, req, resp, id): student=students[id-1] data = json.load(req.bounded_stream) student.update(data) resp.text = json.dumps(student) resp.status = falcon.HTTP_OK resp.content_type = falcon.MEDIA_JSON def on_delete_student(self, req, resp, id): students.pop(id-1) print (students) resp.text = json.dumps(students) resp.status = falcon.HTTP_OK resp.content_type = falcon.MEDIA_JSON app = falcon.App() app.add_route("/students", StudentResource()) app.add_route("/students/{id:int}", StudentResource(), suffix='student') if __name__ == '__main__': serve(app, host='0.0.0.0', port=8000)
Python Falcon - 检查模块
检查模块是一个方便的工具,它提供有关注册路由和 Falcon 应用程序其他组件(例如中间件、接收器等)的信息。
应用程序的检查可以通过两种方式完成:CLI 工具和编程方式。falcon -inspect -tool CLI 脚本从命令行执行,给出声明 Falcon 应用程序对象的 Python 脚本的名称。
例如,检查Studentapi.py中的应用程序对象-
falcon-inspect-app studentapi:app Falcon App (WSGI) Routes: ⇒ /students - StudentResource: ├── GET - on_get └── POST - on_post ⇒ /students/{id:int} - StudentResource: ├── DELETE - on_delete_student ├── GET - on_get_student └── PUT - on_put_student
输出显示资源类中注册的路由和响应程序方法。要以编程方式执行检查,请使用应用程序对象作为检查模块中inspect_app()函数的参数。
from falcon import inspect from studentapi import app app_info = inspect.inspect_app(app) print(app_info)
将上面的脚本保存为inspectapi.py并从命令行运行它。
python inspectapi.py Falcon App (WSGI) Routes: ⇒ /students - StudentResource: ├── GET - on_get └── POST - on_post ⇒ /students/{id:int} - StudentResource: ├── DELETE - on_delete_student ├── GET - on_get_student └── PUT - on_put_student
Python Falcon - Jinja2 模板
Falcon 库主要用于构建 API 和微服务。因此,默认情况下,Falcon 响应程序返回 JSON 响应。但是,如果内容类型更改为falcon.MEDIA_HTML,则可以呈现 HTML 输出。
渲染带有可变数据的 HTML 内容是非常乏味的。为此,使用了 Web 模板库。许多 Python Web 框架都捆绑了特定的模板库。但 Falcon 作为一个极简主义的微型框架并没有预先与任何人捆绑在一起。
Jinja2是许多 Python 框架使用的最流行的模板库之一。在本节中,我们将了解如何将 inja2 与 Falcon 应用程序一起使用。jinja2 是一种快速且设计人员友好的模板语言,易于配置和调试。其沙盒环境可以轻松防止不受信任的代码执行、禁止潜在的不安全数据以及防止跨站脚本攻击(称为XSS 攻击)。
jinja2的另一个非常强大的功能是模板继承,其中您可以定义具有公共设计功能的基本模板,子模板可以覆盖这些功能。
首先,使用 PIP 实用程序在当前 Python 环境中安装jinja2 。
pip3 install jinja2
你好世界模板
jinja2模块定义了一个 Template 类。Template 对象是通过读取包含 HTML 脚本(扩展名为 .html)的文件的内容来获取的。通过调用此 Template 对象的render()方法,可以将 HTML 响应呈现到客户端浏览器。Response 对象的 content_type属性必须设置为falcon.MEDIA_HTML。
让我们将以下 HTML 脚本保存为应用程序文件夹中的hello.py 。
<html> <body> <h2>Hello World</h2> </body> </html>
例子
下面资源类中的 on_get() 响应程序读取此文件并将其呈现为 HTML响应。
import uvicorn import falcon import falcon.asgi from jinja2 import Template class HelloResource: async def on_get(self, req, resp): resp.status = falcon.HTTP_200 resp.content_type = 'text/html' fp=open("hello.html","r") tempobj=Template(fp.read()) resp.body=tempobj.render() app = falcon.asgi.App() hello = HelloResource() app.add_route('/hello', hello) if __name__ == "__main__": uvicorn.run("hello:app", host="0.0.0.0", port=8000, reload=True)
输出
运行上面的Python代码并在浏览器中访问http://localhost:8000/hello链接。
模板变量
jinja2是一个服务器端模板库。通过将 jinja2 模板语言的各种元素作为占位符放置在 HTML 脚本内的适当分隔符内,将网页构建为模板。模板引擎读取 HTML 脚本,用服务器上的上下文数据替换占位符,重新组装 HTML,并将其呈现给客户端。
Template.render ()函数有一个可选的上下文字典参数。该字典的关键属性成为模板变量。这有助于在网页中呈现响应者传递的数据。
例子
在以下示例中,路由/hello/nm注册到资源对象,其中 nm 是路径参数。on_get ()响应程序将其作为上下文传递给从网页获取的模板对象。
import uvicorn import falcon import falcon.asgi from jinja2 import Template class HelloResource: async def on_get(self, req, resp, nm): resp.status = falcon.HTTP_200 resp.content_type = 'text/html' fp=open("hello.html","r") tempobj=Template(fp.read()) resp.body=tempobj.render({'name':nm}) app = falcon.asgi.App() hello = HelloResource() app.add_route('/hello/{nm}', hello) if __name__ == "__main__": uvicorn.run("hello:app", host="0.0.0.0", port=8000, reload=True)
hello.html读取模板变量名中的路径参数。它充当 HTML 脚本中的占位符。它被放入{{和}}符号中,以便其值显示为 HTML 响应。
<html> <body> <h2>Hello {{ name }}</h2> </body> </html>
输出
运行 Python 代码并输入http://localhost:8000/hello/Priya作为 URL。浏览器显示以下输出 -
jinja2 模板中的循环
如果响应者传递任何 Python 可迭代对象(例如列表、元组或字典),则可以使用其循环构造语法在 jinja2 模板内遍历其元素。
{% for item in collection %} HTML block {% endfor %}
在以下示例中,on_get()响应程序将作为dict对象列表的 Students 对象发送到模板list.html。它依次遍历数据并将其呈现为 HTML 表。
import falcon import json from waitress import serve from jinja2 import Template students = [ {"id": 1, "name": "Ravi", "percent": 75.50}, {"id": 2, "name": "Mona", "percent": 80.00}, {"id": 3, "name": "Mathews", "percent": 65.25}, ] class StudentResource: def on_get(self, req, resp): resp.status = falcon.HTTP_OK resp.content_type = falcon.MEDIA_HTML fp=open("list.html","r") tempobj=Template(fp.read()) resp.body=tempobj.render({'students':students})
list.html是 jinja2 模板。它接收作为字典对象列表的学生对象,并将每个键的值放入表的 <td>..<.td> 元素中。
<html> <body> <table border=1> <thead> <tr> <th>Student ID</th> <th>Student Name</th> <th>percentage</th> <th>Actions</th> </tr> </thead> <tbody> {% for Student in students %} <tr> <td>{{ Student.id }}</td> <td>{{ Student.name }}</td> <td>{{ Student.percent }}</td> <td> <a href="#">Edit</a> <a href="#">Delete</a> </td> </tr> {% endfor %} </tbody> </table> </body> </html>
在浏览器地址栏中访问/students路由。学生列表显示在浏览器中。
HTML 表单模板
在本节中,我们将了解 Falcon 如何从 HTML 表单读取数据。让我们将以下 HTML 脚本保存为 myform.html。我们将使用它来获取 Template 对象并渲染它。
<html> <body> <form method="POST" action="http://localhost:8000/students"> <p>Student Id: <input type="text" name="id"/> </p> <p>student Name: <input type="text" name="name"/> </p> <p>Percentage: <input type="text" name="percent"/> </p> <p><input type="submit"> </p> </body> </html>
Falcon App 对象在 Hello.py 文件中声明,该文件还有一个映射到/adddnew路由的资源类。on_get ()响应程序读取myform.html并呈现相同的内容。将显示 HTML 表单。表单通过POST方法提交到/students路径。
为了能够读取表单数据,falcon.RequestOptions类的auto_parse_form_urlencoded属性必须设置为 True。
app = falcon.App() app.req_options.auto_parse_form_urlencoded = True
在这里,我们还从Student.py导入StudentResource类。on_get ()响应程序呈现学生列表。
当用户填写并提交表单时,将调用 on_post() 响应程序。此方法收集req.params属性中的表单数据,该属性只不过是表单元素及其值的字典。然后添加学生词典。
def on_post(self, req,