Python Falcon 简明教程
Python Falcon - Introduction
Falcon 是一个 Python 库,用于开发任务关键型 REST API 和微服务。它同时支持 WSGI 和 ASGI 规范。Falcon 框架由 Kurt Griffiths 于 2013 年 1 月开发。Falcon 的最新版本是 3.1.0,于 2022 年 3 月发布。
Falcon is a Python library for developing mission-critical REST APIs and microservices. It supports both WSGI and ASGI specifications. Falcon framework has been developed by Kurt Griffiths in Jan. 2013. The latest version of Falcon is 3.1.0, released in March 2022.
Falcon 是一款轻量级的 Web 开发框架。其极简主义设计允许开发人员根据需要选择最佳策略和第三方包。
Falcon is a lightweight web development framework. Its minimalist design allows the developer to select the best strategies and 3rd-party packages as required.
Falcon - Important Features
Falcon 根据 Apache 2.0 License 条款发布。
Falcon is released under the terms of the Apache 2.0 License.
Falcon 的一些重要功能包括 −
Some of the important features of Falcon include −
-
Latest version of Falcon supports ASGI, WSGI, as well as WebSocket.
-
Falcon provides native support for asyncio.
-
Its stable interfaces ensure backwards-compatibility
-
Falcon follows REST architectural style for building APIs.
-
Class based construction of HTTP resources.
-
Highly-optimized, extensible code base.
-
Falcon provides easy access to headers and bodies through request and response classes
-
Middleware components and hooks available for DRY request processing.
-
Idiomatic HTTP error responses and exception handling.
Falcon - Design Philosophy
Falcon 最大限度减少对象实例化数量,以免创建对象时花费太多开销,并减少内存使用。同一个实例将用于处理该路由上发来的所有请求。
Falcon minimizes the instantiation of number of objects so as to avoid the expense of creating the object, and to reduce memory usage. The same instance will be used to serve all requests coming in on that route.
-
Exceptions are properly handled by the resource responders (methods such as on_get(), on_post(), etc.). Falcon doesn’t try very hard to protect responder code from itself. A high-quality Falcon API should fulfil following requirements −
-
The Falcon framework is thread-safe. Separate new Request and Response objects are created for each incoming HTTP request. However, a single instance of each resource class attached to a route is shared among all requests. Middleware objects, hooks, and custom error handlers, are also shared. Therefore, your WSGI app as a whole will be thread-safe.
-
Starting with version 3.0, Falcon supports asyncio. Use the falcon.asgi.App class to create an async application, and serve it via an ASGI application server such as Uvicorn.
-
The async version of Falcon supports the ASGI WebSocket protocol.
Falcon - Comparison with Other Frameworks
Python Web 框架有两大类 − full-stack 和 micro 框架。
There are two major categories of Python web frameworks − full-stack and micro frameworks.
-
Full-stack frameworks come with built-in features and libraries. Django, Turbogears, and Web2Py are full-stack frameworks.
-
In contrast, micro-frameworks are minimalistic, only providing the bare minimum; thus gives developers the freedom to choose official or third-party extensions and only include plugins which they need. Flask, Falcon, Pyramid belong to micro framework category.
我们根据以下参数将 Falcon 框架与不同框架进行比较 −
We compare Falcon framework against different frameworks on the basis of the following parameters −
Performance
Falcon 应用非常快,与 Flask 和 Pyramid 等微框架相比。而全栈框架通常很慢。
Falcon application is very fast, in comparison with micro frameworks such as Flask and pyramid. The full stack frameworks are generally slow.
REST Support
Falcon 是一个旨在用于开发 REST API 和微服务的框架。FastAPI 也支持 REST 开发。Flask 和 Django 没有内置的 REST 支持。但是,可以使用扩展名启用它。
Falcon is intended to be a framework of choice for development of REST APIs and microservices. FastAPI also encourages REST development. Flask and Django don’t have built-in REST support. However, it can be enabled using extensions.
Templating
Falcon 应用程序不应提供模板网页。它未与任何模板库捆绑在一起。不过,可以使用 jinja2 或 Macho 库。另一方面,Flask 对 jinja2 有内置支持。Django 有自己的模板库。FastAPI 还可以处理任何选择的模板库。
Falcon app is not supposed to serve template web pages. It is not bundled with any templating library. However, one can use jinja2 or Macho libraries. On the other hand, Flask has a built-in support for jinja2. Django has its own templating library. FastAPI also can handle any template library of choice.
Database Support
在 Falcon 中,没有内置的数据库支持。可以使用 SQLAlchemy 模型与关系数据库(如 MyQL、PostgreSQL、SQLite 等)进行交互。另一方面,Django 具有自己的 ORM 框架,可以开箱即用。
In Falcon database support is not built-in. It is possible to use SQLAlchemy models to interact with relational databases like MyQL, PostgreSQL, SQLite etc. Django on the other hand has its own ORM framework for use out of the box.
Flask 应用程序还可以通过 Flask 扩展与数据库进行交互。TurboGears 的早期版本与 SQLObject ORM 库兼容。较新版本与 SQLAlchemy 兼容。
A Flask application also can interact with databases through Flask extensions. Earlier versions of TurboGears had compatibility with SQLObject ORM library. The newer version is compatible with SQLAlchemy.
Flexibility
Falcon 应用程序非常灵活。它是要求高度定制和性能调优的应用程序的理想选择。FastAPI 和 Flask 也能灵活地进行编码,并且不会限制用户使用特定的项目或代码布局。
Falcon applications are very flexible. It is ideal for applications that require a high degree of customization and performance tuning. FastAPI and Flask too are flexible to code and doesn’t restrict users to a particular project or code layout.
Security
Falcon 没有内置的安全保障支持。Django 和 FastAPI 等其他框架可确保高度的安全性。Flask 也提供了出色的防护功能,可以抵御 CSRF 和 XSS 攻击等安全威胁。
Falcon has no built-in support to ensure security. Other frameworks like Django and FastAPI ensure high degree of security. Flask also provides excellent protection against security threats such as CSRF and XSS attacks.
Python Falcon - Environment Setup
最新版本的 Falcon 需要 Python 3.5 或更高版本。最简单、也同时是推荐的安装方法是使用 PIP 安装程序,最好是在虚拟环境中安装。
The latest version of Falcon requires Python 3.5 or newer version. The easiest as well as recommended way to install Falcon is with PIP installer, preferably in a virtual environment.
可以通过运行以下命令安装最新稳定版本 −
The latest stable version can be installed by running the following command −
pip3 install falcon
要验证是否已成功安装,请导入该库并检查其版本。
To verify if the installation has been performed successfully, import the library and check its version.
>>> import falcon
>>>falcon.__version__
'3.1.0'
要安装最新测试版,应使用以下命令 −
To install the latest beta version, following command should be used −
pip3 install --pre falcon
Falcon 从早期版本开始就支持 WSGI。Falcon 应用程序可以在 Python 的标准库模块 wsgiref 的帮助下使用内置 WSGI 服务器运行。但是,它不适用于生产环境,为此需要使用 WSGI 服务器,例如 gunicorn、waitress 或 uwsgi。
Right from the early version, Falcon supports WSGI. A Falcon app can be run with the help of built-in WSGI server in Python’s standard library module wsgiref. However, it is not suitable for production environment, for which WSGI servers such as gunicorn, waitress or uwsgi are required.
对于 Windows 上的 Falcon,可以使用 Waitress ,一个生产级的纯 Python WSGI 服务器。与往常一样,使用 pip 安装程序进行安装。
For Falcon on Windows, one can use Waitress, a production-quality, pure-Python WSGI server. As usual, install it with pip installer.
pip3 install waitress
Gunicorn 服务器无法安装在 Windows 上。但是,可以在 Windows 10 上的 Windows 子系统 Linux ( WSL ) 环境中使用它。要在 Linux、WSL 或 Docker 容器中使用 gunicorn,请使用
The Gunicorn server can’t be installed on Windows. However, it can be used inside a Windows Subsystem Linux (WSL) environment on Windows 10. For using gunicorn on Linux, WSL or inside Docker containers, use
pip3 install gunicorn
如果你想运行异步 Falcon 应用程序,则需要一个与 ASGI 兼容的应用程序服务器。Uvicorn 服务器可在 Windows 和 Linux 系统上使用。
If you want to run an asynchronous Falcon app, an ASGI compliant application server is required. The Uvicorn server can be used on Windows as well as Linux systems.
pip3 install uvicorn
Python Falcon - WSGI vs ASGI
Web Server Gateway Interface(WSGI)
一些最流行的 Python Web 框架实现了 WSGI(代表 Web Server Gateway Interface )。WSGI 本质上是一组规范,用于 Web 服务器和 Web 应用程序之间的通用接口,由 Web 服务器软件实现,用于处理基于 Python 的 Web 应用程序的请求。WSGI 规范最初于 2003 年引入(PEP 333),并于 2010 年进行更新(PEP 3333)。
Some of the most popular Python web frameworks implement WSGI (stands for Web Server Gateway Interface). WSGI is essentially a set of specifications for a universal interface between web server and web applications, to be implemented by web server software for handling requests from Python-based web application. WSGI specifications were first introduced in 2003 (PEP 333) and later updated in 2010 (PEP 3333).
服务器通过传递以下参数来调用 WSGI 应用程序对象 −
A WSGI Application object is invoked by the server by passing the following arguments −
-
environ − A Python dict object which is similar to CGI environment variables and certain WSGI specific variables.
-
start_response − A callback function to be used by the application to return its response along with headers and status code.
此对象可以是 Python 中的任意可调用对象,例如带 call() 方法的函数、方法、类或其实例。此应用程序对象必须返回一个包含单个字节字符串的迭代器。
This object can be any callable object as in Python such as a function, method, a class or its instance with call() method available to it. This application object must return an iterator consisting of a single byte string.
def application (environ, start_response):
...
...
return [("Hello World!".encode("utf-8")]
但是,启用 WSGI 的服务器在运行时是同步的,因此,应用程序不够高效。Python 通过引入 asyncio 模块作为标准库的一部分,从 3.4 版开始支持异步编程。
However, WSGI-enabled servers are synchronous in operation, because of which the applications are not that efficient. Python started asynchronous programming support with version 3.4 by introducing the asyncio module as a part of the standard library.
asyncio 模块提供在 Python 应用程序中并入并发编程样式的能力(通常称为协作式多任务处理)。在这种方法中,操作系统不会妨碍不同进程之间的上下文切换。取而代之的是,进程定期让步以容纳其他进程,以便许多应用程序可以同时运行。
The asyncio module provides the ability to incorporate in Python applications a style of concurrent programming (which is often called cooperative multitasking). In this approach, the operating system doesn’t obstruct the context switching among different processes. Instead, a process yields periodically to accommodate other processes so that many applications can run simultaneously.
在 Python 的 3.5 版中,添加了这两个关键字 async 和 await 。使用 async 关键字定义的 Python 函数称 coroutine 为,因此不能像普通函数一样运行。取而代之的是,我们需要使用 asyncio.run (coroutine) 调用它。可以通过 await 关键字使协程的执行暂停,直到另一个协程完成。
In Python’s version 3.5, these two keywords async and await were added. A Python function defined with the async keyword becomes a coroutine and hence can’t be run like a normal function. Instead, we need to call it using asyncio.run (coroutine). The execution of a coroutine can be made to pause till the completion of another coroutine by the await keyword.
import asyncio
async def main():
print('hello')
await asyncio.sleep(5)
print('world')
asyncio.run(main())
Asynchronous Server Gateway Interface(ASGI)
ASGI 代表 Asynchronous Server Gateway Interface (根据其官方文档,它是 WSGI 的精神继承者),它为 Python Web 服务器、应用程序和框架增加了异步功能。
ASGI stands for Asynchronous Server Gateway Interface (as per its official documentation, it is a spiritual successor to WSGI), it adds the async capabilities to Python web servers, applications and frameworks.
ASGI 应用程序是一个异步可调用对象(用户定义的函数或具有 call() 方法的类的对象)。它获取三个参数,如下所示:
An ASGI application is an asynchronous callable object (a user-defined function or an object of a class having call() method). It takes three arguments as follows −
-
Scope − A dict containing details of a specific connection
-
Send − An asynchronous callable, by which event messages can be sent to the client
-
Receive − Another asynchronous callable. The application can receive event messages from the client.
下面是一个异步函数表示的简单 ASGI 应用程序的原型 −
Following is the prototype of a simple ASGI application represented by an asynchronous function −
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 对象的一个实例。
To create a simple Hello World Falcon app, start with importing the library and declaring an instance of App object.
import falcon
app = falcon.App()
Falcon 遵循 REST 架构风格。声明一个资源类,其中包括一个或多个表示标准 HTTP 动词的方法。以下 HelloResource 类包含 on_get() 方法,预期在服务器收到 GET 请求时调用此方法。该方法返回 Hello World 响应。
Falcon follows REST architectural style. Declare a resource class that includes one or more methods representing the standard HTTP verbs. The following HelloResource class contains on_get() method that is expected to get called when the server receives GET request. The method returns Hello World response.
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,来处理传入请求。
To invoke this method, we need to register it to a route or URL. The Falcon application object handles the incoming requests by assigning the handler methods to corresponding URLs by add_rule method.
hello = HelloResource()
app.add_route('/hello', hello)
Falcon 应用程序对象只不过是一个 WSGI 应用程序。我们可以使用 Python 标准库的 wsgiref 模块中的内置 WSGI 服务器。
The Falcon application object is nothing but a WSGI application. We can use the built-in WSGI server in the wsgiref module of Python’s standard library.
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()
Example
让我们将所有这些代码段放入 hellofalcon.py
Let us put all these code fragments in 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()
从命令提示符运行此代码。
Run this code from the command prompt.
(falconenv) E:\falconenv>python hellofalcon.py
Serving on port 8000...
Python Falcon - Waitress
不建议在生产环境中使用开发服务器。开发服务器的效率、稳定性或安全性都不高。
The development server is not recommended to be used in production environment. The development server is not efficient, stable, or secure.
Waitress 是一个生产级的纯 Python WSGI 服务器,性能非常不错。除了生活在 Python 标准库中的依赖项之外,它没有其他依赖项。它在 Unix 和 Windows 上的 CPython 上运行。
Waitress is a production-quality pure-Python WSGI server with very acceptable performance. It has no dependencies except ones that live in the Python standard library. It runs on CPython on Unix and Windows.
确保 Waitress 服务器已安装在工作环境中。该库包含 serve 类,其对象负责处理传入请求。serve 类的构造函数需要三个参数。
Make sure that Waitress server has been installed in the working environment. The library contains serve class whose object is responsible for serving the incoming requests. The constructor of serve class requires three parameters.
serve (app, host, port)
falcon 应用程序对象是 app 参数。默认情况下,host 和 port 的默认值为 localhost 8080。listen 参数是字符串,作为 host:port 参数的组合,默认值为“0.0.0.0:8080”
The falcon application object is the app parameter. The default values of host and port are localhost 8080 by default. The listen parameter is a string as a combination of host:port parameter defaulting to '0.0.0.0:8080'
Example
在 hellofalcon.py 代码中,我们导入 serve 类,而不是 simple_server ,并按如下方式实例化它的对象 −
In the hellofalcon.py code, we import the serve class instead of simple_server and instantiate its object as follows −
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 使 localhost 公开可见。
Execute hellofalcon.py and visit the http://localhost:8000/hellolink in the browser as before. Note that the host 0.0.0.0 makes the localhost publicly visible.
还可以从命令行启动 Waitress 服务器,如下所示 −
The Waitress server can be launched from the command line also, as shown below −
waitress-serve --port=8000 hellofalcon:app
Python Falcon - ASGI
ASGI 代表 Asynchronous Server Gateway Interface (根据其官方文档,它是 WSGI 的精神继承者),它为 Python Web 服务器、应用程序和框架增加了异步功能。
ASGI stands for Asynchronous Server Gateway Interface (as per its official documentation, it is a spiritual successor to WSGI), it adds the async capabilities to Python web servers, applications and frameworks.
要运行异步 web 应用程序,我们需要一个 ASGI 应用程序服务器。常用的选择包括 −
For running an async web application, we’ll need an ASGI application server. Popular choices include −
-
Uvicorn
-
Daphne
-
Hypercorn
在本教程中,我们将在 async 示例中使用 Uvicorn 服务器。
We shall use Uvicorn server for async examples in this tutorial.
Hello World - ASGI
Falcon 的 ASGI 相关功能在 falcon.asgi 模块中可用。因此,我们需要在开头将其导入。
The ASGI related functionality of Falcon is available in the falcon.asgi module. Hence, we need to import it in the beginning.
import falcon
import falcon.asgi
虽然资源类与上一个示例中相同,但必须使用 async 关键字声明 on_get() 方法。我们必须获取 Falcon 的 ASGI 应用程序的实例。
While the resource class remains the same as in the previous example, the on_get() method must be declared with async keyword. we have to obtain the instance of Falson’s ASGI app.
app = falcon.asgi.App()
Example
因此,针对 ASGI 的 hellofalcon.py 如下所示:
Hence, the hellofalcon.py for ASGI will be as follows −
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 服务器,如下所示:
To run the application, start the Uvicorn server from the command line as follows −
uvicorn hellofalcon:app –reload
Output
打开浏览器并访问 http://localhost:/8000/hello 。您将在浏览器窗口中看到响应。
Open the browser and visit http://localhost:/8000/hello. You will see the response in the browser window.

Python Falcon - Uvicorn
Uvicorn 使用 uvloop 和 httptools 库。它还提供对 HTTP/2 和 Websocket 的支持,而 WSGI 无法处理它们。 uvloop 类似于内置 asyncio 事件循环。 httptools 库处理 http 协议。
Uvicorn uses uvloop and httptools libraries. It also provides support for HTTP/2 and WebSockets, which cannot be handled by WSGI. uvloop is similar to the built-in asyncio event loop. httptools library handles the http protocols.
Falcon 的 ASGI 兼容应用程序在 Uvicorn 服务器上使用以下命令启动:
Falcon’s ASGI compliant application is launched on Uvicorn server with following command −
Uvicorn hellofalcon:app – reload
--reload 选项启用调试模式,以便 app.py 中的任何更改都将自动反映,并且客户端浏览器上的显示将自动刷新。此外,可以使用以下命令行选项:
The --reload option enables the debug mode, so that any changes in app.py will be automatically reflected and the display on the client browser will be automatically refreshed. In addition, the following command-line options may be used −
--host TEXT |
Bind socket to this host. [default 127.0.0.1] |
--port INTEGER |
Bind socket to this port. [default 8000] |
--uds TEXT |
Bind to a UNIX domain socket. |
--fd INTEGER |
Bind to socket from this file descriptor. |
--reload |
Enable auto-reload. |
--reload-dir PATH |
Set reload directories explicitly, default current working directory. |
--reload-include TEXT |
Include files while watching. Includes '*.py' by default |
--reload-exclude TEXT |
Exclude while watching for files. |
--reload-delay FLOAT |
Delay between previous and next check default 0.25 |
--loop [auto |
asyncio |
uvloop] |
Event loop implementation. [default auto] |
--http [auto |
h11 |
httptools] |
HTTP protocol implementation. [default auto] |
--interface auto |
asgi |
wsgi |
Select application interface. [default auto] |
--env-file PATH |
Environment configuration file. |
--log-config PATH |
Logging configuration file. Supported formats .ini, .json, .yaml. |
--version |
Display the Uvicorn version and exit. |
--app-dir TEXT |
Look for APP in the specified directory default current directory |
--help |
Show this message and exit. |
Uvicorn 服务器也可以在程序内部启动,而不是通过上述命令行。要执行该操作,请导入 uvicorn 模块并调用 uvicorn.run() 方法,如下所示 −
The Uvicorn server can also be launched from within the program instead of the above command line. To do that, import uvicorn module and call uvicorn.run() method as shown below −
import uvicorn
if __name__ == "__main__":
uvicorn.run("hellofalcon:app", host="0.0.0.0", port=8000, reload=True)
相应地更改 hellofalcon.py 代码,并从命令提示符执行相同操作。可以使用 curl 命令或在浏览器中验证结果,如前所述。
Change the hellofalcon.py code accordingly, and execute the same from command prompt. The result can be verified by the curl command or in the browser as explained earlier.
Python Falcon - API Testing Tools
Falcon 是适合开发 API 的极简主义框架。API 是两个应用程序之间的接口。在将其发布到生产环境中之前,API 开发人员需要测试其功能性、可靠性、稳定性、可扩展性和性能等。
Falcon is a minimalistic framework suitable for developing APIs. An API is an interface between two applications. The API developer needs to test its functionality, reliability, stability, scalability, and performance etc. before releasing it for use in production environment.
为此提供各种 API 测试工具。在本节中,我们将学习如何使用命令行工具 Curl 和 HTTPie ,以及称为 Postman 的 GUI 工具。
Various API testing tools are available for this purpose. In this section, we shall learn how to use command line tools Curl and HTTPie, and a GUI tool called Postman.
cURL
cURL 是一个开源项目,它提供 libcurl 库和一个名为 curl 的命令行工具,可以使用各种协议传输数据。它支持超过 20 种协议,包括 HTTP。cURL 的缩写表示为客户端 URL。从命令行使用 Curl 的语法为 −
cURL is an open source project that provides libcurl library and a command line tool called curl that enables transferring data using various protocols. More than 20 protocols including HTTP are supported. The acronym cURL stands for Client URL. The syntax for using Curl from command line is −
curl [options] [URL1, URL2,..]
URL 参数由协议相关的一个或多个 URL 字符串组成。Curl 命令可以使用各种选项来自定义。一些重要的命令行选项如下 −
The URL parameter consists of protocol dependent, one or more URL strings. The Curl command can be customized with various options. Some of the important command line options are as follows −
-
– X: Mention the request method. By default, Curl assumes GET to be the request method. To send POST, PUT or DELTETE requests, this option must be used. For example −
Curl –X DELETE http://localhost:8000/student/1
-
– H: This option is used to add headers in the request. For example −
Curl –H "Content-Type: application/json" -X GET
http://localhost:8000/students
-
– i: When this option is included in the command line, all the response headers are displayed. For example −
Curl –I –X DELETE http://localhost:8000/student/2
-
– d: To include data in the HTTP request for processing, we have to use this option, particularly when POST or PUT request is needed.
Curl –H "Content-Type: application/json" -X PUT -d
"{"""marks""":"""50"""}" http://localhost:8000/students/3
HTTPie
HTTPie 是用 Python 编写的命令行工具。据说它是一个“适合人类的 cURL 类似工具”。它支持表单和文件上传,并生成格式良好的彩色终端输出。与 Curl 相比,其富有表现力和直观的语法使它更易于使用。
The HTTPie is a command line tool written in Python. It is said to be a "cURLlike tool for humans". It supports forms and file uploads and generates nicely formatted colorized terminal output. Its expressive and intuitive syntax makes it easier to use as compared to Curl.
Postman
Postman 是一款非常流行的 API 测试工具。Gemellini 是一个 GUI 应用程序,它与 Curl 和 HTTPie 相反。它既可用作浏览器插件,也可作为一个桌面应用程序。由于浏览器插件不接受基于本地的 API 请求,我们需要从 https://www.postman.com/downloads. 下载桌面版本。
Postman is a very popular API testing tool. It is a GUI app as against Curl and HTTPie. It is available in the form of a browser plugin as well as a desktop application. As the browser plugin doesn’t accept requests for localhost based APIs, we need to download the desktop version from https://www.postman.com/downloads.
在完成基于向导的安装后,启动 Postman 应用程序并创建一个新请求。
After completing the wizard based installation, start the Postman app and create a new request.

该下拉框显示可供选择的各种 HTTP 请求类型。
The dropdown shows various HTTP request types to choose from.

在请求 URL 字段中输入 http://localhost:8000/hello 。右侧的响应窗格显示结果。
Enter http://localhost:8000/hello in the request URL field. The response pane on the right shows the result.

我们稍后将在针对 SQLite 数据库测试 Falcon API 的 CRUD 操作时使用对应的请求类型。
We shall use the corresponding request types later when we test the Falcon API for CRUD operations on a SQLite database.
Python Falcon - Request & Response
HTTP 协议指出,客户端向服务器发送一个 HTTP 请求,该请求中应用了某些业务逻辑,然后生成响应并将其重定向到客户端。如果在这两个之间进行同步传输,Python 框架会使用 WSGI 标准,而异步传输遵循 ASGI 标准。Falcon 支持这两种标准。
The HTTP protocol states that the client sends a HTTP request to the server where certain business logic is applied and a response is formulated, which is redirected towards the client. In case of synchronous transfer between the two, Python frameworks use WSGI standard, while asynchronous transfer follows ASGI standard. Falcon supports both.
WSGI/ASGI 服务器在上下文数据中提供 Request 和 Response 对象。这些对象被响应者、钩子、中间件等用作参数。对于 WSGI 应用程序,它处理 falcon.Request 类的实例。在 ASGI 应用程序中,它表示 falcon.asgi.Request 类。虽然这两类不同,但它们被设计为具有相似的属性和方法,以便最大限度地减少混淆并实现更简单的移植。
The WSGI/ASGI server provides Request and Response objects in the context data. These objects are used by the responders, hooks, middleware etc. as the parameters. For WSGI apps, the instance of falcon.Request class is processed. In ASGI apps, it represents falcon.asgi.Request class. though different, both the classes are designed to have similar properties and methods so as to minimize the confusion and allow easier portability.
Request
Request 对象表示 HTTP 请求。由于它是由服务器提供的,因此该对象不应由响应者方法直接实例化。此对象提供了以下属性和方法,供响应者、钩子和中间件方法在其中使用 -
The Request object represents the HTTP request. Since it is provided by the server, this object is not meant to be instantiated directly by the responder methods. This object provides the following properties and methods to be used inside the responder, hooks and middleware methods −
-
method − HTTP method requested (e.g., 'GET', 'POST', etc.)
-
host − Host request header field
-
port − Port used for the request. Default one for the given schema is returned (80 for HTTP and 443 for HTTPS)
-
uri − The fully-qualified URI for the request.
-
path − Path portion of the request URI (not including query string).
-
query_string − Query string portion of the request URI, without the preceding '?' character.
-
cookies − A dict of name/value cookie pairs.
-
content_type − Value of the Content-Type header, or None if the header is missing.
-
stream − File-like input object for reading the body of the request, if any. This object provides direct access to the server’s data stream and is non-seekable.
-
bounded_stream − file-like wrapper around stream
-
headers − Raw HTTP headers from the request
-
params − The mapping of request query parameter names to their values.
-
get_cookie_values(name) − Return all values provided in the Cookie header for the named cookie. Alias for the cookies property.
-
get_media() − Return a deserialized form of the request stream. Similar to media property.
-
get_param(name) − Return the raw value of a query string parameter as a string. If an HTML form with application/x-wwwform-urlencoded media type is POSTed, Falcon can automatically parse the parameters from the request body and merge them into the query string parameters. To enable this functionality, set auto_parse_form_urlencoded to True via App.req_options.
Response
Response 对象表示服务器对客户端的 HTTP 响应。与 Request 对象一样,Response 对象也不应该由应答者直接实例化。
The Response object represents the server’s HTTP response to the client. Like the Request object, the Response object too is not meant to be directly instantiated by the responder.
应答者、hook 函数或中间件方法通过访问以下属性和方法来操作该对象−
The responder, hook function or middleware method manipulates this object by accessing following properties and methods −
-
status − HTTP status code e.g., '200 OK'. This may be set to a member of http.HTTPStatus, an HTTP status line string or byte string, or an int. Falcon provides a number of constants for common status codes, starting with the HTTP_ prefix, as in − falcon.HTTP_204.
-
media − A serializable object supported by the media handlers configured via falcon.RequestOptions.
-
text − A string representing response content.
-
body − Deprecated alias for text.
-
data − A Byte string representing response content.
-
stream − A file-like object representing response content.
-
content_length − Set the Content-Length header. It sets the content length manually when either text or data property are not set.
-
content_type − Sets the Content-Type header. Falcon’s predefined constants for common media types include 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, and falcon.MEDIA_GIF.
-
append_header (name, value) − Set or append a header for this response. Used to set cookies.
-
delete_header (name) − Delete a header that was previously set for this response.
-
get_header (name) − Retrieve the raw string value for the given header.
-
set_cookie (name, value) − Set a response cookie. This method can be called multiple times to add one or more cookies to the response.
-
set_header (name, value) − Set a header for this response to a given value.
-
set_stream (stream, content_length) − Set both stream and content_length.
-
unset_cookie (name, domain=None, path=None) − Unset a cookie in the response. This method clears the contents of the cookie, and instructs the user agent to immediately expire its own copy of the cookie.
Python Falcon - Resource Class
Falcon 的设计借鉴了 REST 架构样式中的几个关键概念。REST 的含义是 Relational State Transfer 。REST 定义了 Web 应用程序架构的行为方式。
Falcon’s design borrows several key concepts from the REST architectural style. REST stands for Relational State Transfer. REST defines how the architecture of web applications should behave.
REST 是一种基于资源的架构。在此,REST 服务器承载的所有内容(无论是文件、图像还是数据库中表格中的行)都被视为资源,可能有多种表现形式。REST API 提供对这些资源的受控访问,以便客户端可以检索和修改它们。
REST is a resource-based architecture. Here, everything that the REST server hosts, be it a file, an image or row in a table of a database, is treated as a resource, which may have many representations. The REST API provides a controlled access to these resources so that the client can retrieve and modify them.
服务器上的资源应仅有一个统一资源标识符 (URI)。它只标识资源;它不指定对该资源执行的操作。相反,用户从一组标准方法中进行选择。用于对资源执行操作的 HTTP 动词或方法。POST、GET、PUT 和 DELETE 方法分别执行 CREATE、READ、UPDATE 和 DELETE 操作。
A resource with the server should have only one uniform resource identifier (URI). It only identifies the resource; it does not specify what action to take on that resource. Instead, users choose from a set of standard methods. HTTP verb or method to be used for the operation on the resources. The POST, GET, PUT and DELETE methods perform CREATE, READ, UPDATE and DELETE operations respectively.
Falcon 使用普通的 Python 类来表示资源。此类在应用程序中充当控制器。它将传入请求转换为一个或多个内部操作,然后根据这些操作的结果将响应返回给客户端。
Falcon uses normal Python classes to represent resources. Such a class acts as a controller in your application. It converts an incoming request into one or more internal actions, and then compose a response back to the client based on the results of those actions.

每个资源类定义各种 "responder" 方法,每个方法对应于资源允许的一种 HTTP 方法。响应程序名称以 "on_" 开头,并且根据它们处理的 HTTP 方法命名,例如 on_get(), on_post(), on_put(), 等。
Each resource class defines various "responder" methods, one for each HTTP method the resource allows. Responder names start with "on_" and are named according to which HTTP method they handle, as in on_get(), on_post(), on_put(), etc.
在 hellofalcon.py 以上使用的示例代码中, HelloResource (资源类)具有 on_get() 响应程序方法。响应程序必须始终定义至少两个参数来接收请求和响应对象。
In the hellofalcon.py example code used above, HelloResource (the resource class) has an on_get() responder method. Responders must always define at least two arguments to receive Request and Response objects.
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 关键字进行定义。
For ASGI apps, the responder must be a coroutine function, i.e. must be defined with async keyword.
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 object 表示传入的 HTTP 请求。可以通过此对象访问请求相关的请求头、查询字符串参数和其他元数据。
The Request object represents the incoming HTTP request. Request headers, query string parameters, and other metadata associated with the request can be accessed through this object.
Response 对象表示应用程序对请求的 HTTP 响应。此对象的属性和方法设置状态、标头和正文数据。它还公开了一个类似 dict 的上下文属性,用于将任意数据传递给挂钩和其他中间件方法。
The Response object represents the application’s HTTP response to the request. Properties and methods of this object set status, header and body data. It also exposes a dict-like context property for passing arbitrary data to hooks and other middleware methods.
请注意 HelloResource 在上面的示例中只是一个普通的 Python 类。它可以具有任何名称;但是,惯例是将其命名为 xxxResource 。
Note that HelloResource in the above example is just a normal Python class. It can have any name; however, the convention is to name it as xxxResource.
Python Falcon - App Class
此类是基于 Falcon 的 WSGI 应用程序的主要入口点。此类的实例提供了一个可调用的 WSGI 接口和一个路由引擎。
This class is the main entry point into a Falcon-based WSGI app. An instance of this class provides a callable WSGI interface and a routing engine.
import falcon
app = falcon.App()
此类的 init() 构造函数采用以下关键字参数 −
The init() constructor of this class takes the following keyword arguments −
-
media_type − media type to use when initializing RequestOptions and ResponseOptions. Falcon allows for easy and customizable internet media type handling. By default, Falcon only enables handlers for JSON and HTML (URL-encoded and multipart) forms.
-
request_type − Default value of this argument is falcon.Request class.
-
response_type − Default value of this argument is falcon.Response class.
为了使 App 对象可调用,其类有一个 call() 方法。
In order to make the App object callable, its class has a call() method.
__call__(self, env, start_response)
这是一个 WSGI 应用程序方法。WSGI 开发服务器或其他生产服务器(Waitress/Uvicorn)使用此对象启动服务器实例并侦听来自客户端的请求。
This is a WSGI app method. The WSGI development server or other production servers (Waitress/Uvicorn) use this object to launch the server instance and listen to the requests from the client.
App 类还定义了 add_route() 方法。
The App class also defines the add_route() method.
add_route(self, uri_template, resource)
此方法有助于将 URI 路径与其资源类中的对象相关联。传入请求按一组 URI 模板路由到资源。如果路径与给定路由的模板匹配,则该请求被传递到相关资源以进行处理。根据请求方法,将调用各自的应答器方法。
This method helps in associating a URI path with an object of resource class. Incoming requests are routed to resources based on a set of URI templates. If the path matches the template for a given route, the request is then passed on to the associated resource for processing. Depending on the request method, the respective responder methods are called.
Example
让我们向 on_post() 类中添加 HelloResource 应答器方法,并测试 GET 和 POST 请求的端点。
Let us add on_post() responder method to HelloResource class and test the endpoints for GET as well as POST requests.
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)
Output
使用 Waitress 服务器运行应用程序,并使用 Curl 检查响应。对于 GET 请求的响应,使用以下命令 −
Run the application using Waitress server and check the responses using Curl. For response to GET request, using following command −
C:\Users\User>curl localhost:8000/hello
Hello World
我们通过 POST 方法将一些数据发送到 /hello URL,如下所示 −
We send some data to the /hello URL by POST method as follows −
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() 方法。
To add a route to a directory of static files, Falcon has add_static_route() method.
add_static_route(self, prefix, directory, downloadable=False,
fallback_filename=None)
prefix 参数是要匹配此路由的路径前缀。directory 参数是要从中提供文件的文件目录。downloadable 参数设置为 True,如果您希望在响应中包含 ContentDisposition 头。 fallback_filename 默认情况下为无,但在请求的文件未找到时可以指定。
The prefix argument is the path prefix to match for this route. The directory argument is the source directory from which to serve files. The downloadable argument is set to True if you want to include a ContentDisposition header in the response. The fallback_filename is by default None but can be specified when the requested file is not found.
add_error_handler() 方法用于为一个或多个异常类型注册处理程序。
The add_error_handler() method is used to register a handler for one or more exception types.
add_error_handler(self, exception, handler=None)
可异步调用 App 类具有相同的方法。它在 falcon.asgi 模块中定义。
The ASGI callable App class possesses the same methods. It is defined in falcon.asgi module.
import falcon.asgi
app=falcon.asgi.App()
请注意,ASGI 应用程序中资源类的响应器必须是 coroutines (使用 async 关键字定义),而不是正常方法。
Note that the responders of the resource class in an ASGI application must be coroutines (defined with async keyword) instead of normal methods.
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 - Routing
Falcon 采用 RESTful 架构样式。因此,它使用基于资源的路由。资源类负责通过响应器处理 HTTP 方法,响应器本质上是类方法,名称以 on_ 开头,以小写 HTTP 方法名称结尾(例如, on_get(), on_patch(), on_delete(), 等)。Falcon 应用程序对象的 add_route() 方法将其路由器与其资源类的实例相关联。
Falcon adopts RESTful architectural style. Hence it uses resource based routing. A resource class is responsible for handling the HTTP methods by the responders, which are essentially class methods with a name that starts with on_ and ends in the lowercased HTTP method name (e.g., on_get(), on_patch(), on_delete(), etc.). The add_route() method of the Falcon Application object associates its router with an instance of resource class.
在上面使用的 Hellofalcon.py 示例中, on_get() 和 on_post() 响应器在客户端通过 GET 和 POST 方法请求 /hello 路由时被调用。
In the Hellofalcon.py example used above, the on_get() and on_post() responders are invoked when the /hello route is requested by the client by GET and POST method respectively.
如果没有路由与请求相匹配,则会引发 HTTPRouteNotFound 的实例。另一方面,如果匹配到路由,但资源并未实现对所请求 HTTP 方法的响应器,则默认响应器将引发 HTTPMethodNotAllowed 的实例。
If no route matches the request, an instance of HTTPRouteNotFound is raised. On the other hand, if a route is matched but the resource does not implement a responder for the requested HTTP method, a default responder raises an instance of HTTPMethodNotAllowed.
Field Converters
Falcon 的路由机制允许 URL 向响应器传递参数。URL 包含三个部分:协议(例如 http:// 或 https:// ),后跟 IP 地址或主机名。URL 的其余部分在主机名之后的第一个 / 之后称为路径或端点。要传递的参数在端点之后。
Falcon’s routing mechanism allows URLs to pass parameters to the responders. The URL comprises of three parts: The protocol (such as http:// or https://) followed by the IP address or hostname. The remaining part of the URL after first / after the hostname is called as the path or endpoint. Parameters to be passed are after the endpoint.

它充当资源标识符,例如唯一 ID 或主键。参数名用大括号括起来。路径参数的值除了请求和响应之外,还会进入在响应器方法中定义的参数。
This acts as a resource identifier such as a unique ID or primary key. The parameter names are enclosed in curly brackets. Value of a path parameter goes to the argument defined in the responder method in addition to request and response.
在以下示例中,路由器将资源类对象与其由端点之后的参数组成的 URL 相关联。
In the following example, the router associates the resource class object with a URL consisting of a parameter after the endpoint.
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 。
We can see that the on_get() responder method has an additional parameter nm to accept the data parsed from the URL route. Let us test http://localhost:8000/hello/Priya with HTTPie tool.
>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 的路由引擎有以下 built-in field converters ,可以使用它们将它们读取到其他数据类型中。
The default data type to which the path parameters are parsed to is str (i.e. string). However, Falcon’s router engine has the following built-in field converters using which they can be read into other data types as well.
-
IntConverter − This class is defined in falcon.routing module. The constructor uses the following arguments −
IntConverter(num_digits=None, min=None, max=None)
app.add_route('/student/{rollno:int(1,1,100}', StudentResource())
-
UUIDConverter − This class in the falcon.routing module gives converts a string of 32 hexadecimal digits into a UUID (Universal Unique Identifier).
-
DateTimeConverter − Converts the parameter string to a datetime variable. The parameter must be a string in any format recognized by strptime() function, the default being '%Y-%m-%dT%H:%M:%SZ'.
格式字符串使用以下格式代码 −
Format string uses the following format codes −
%a |
Abbreviated weekday name |
Sun, Mon |
%A |
Full weekday name |
Sunday, Monday |
%d |
Day of the month as a zero-padded decimal |
01, 02 |
%-d |
day of the month as decimal number |
1, 2.. |
%b |
Abbreviated month name |
Jan, Feb |
%m |
month as a zero padded decimal number |
01, 02 |
%B |
Full month name |
January, February |
%-y |
year without century as a decimal number |
0, 99 |
%Y |
year with century as a decimal number |
2000, 1999 |
%H |
hour(24 hour clock) as a zero padded decimal number |
01, 23 |
%p |
locale’s AM or PM |
AM, PM |
%-M |
Minute as a decimal number |
1, 59 |
%-S |
Second as a decimal number |
1, 59 |
在以下示例中, add_route() 函数将一个 URL 与带有两个参数的 Resource 对象关联在一起。默认情况下,第一个参数 nm 为字符串。第二个参数 age 使用 IntConverter 。
In the following example, the add_route() function associates a URL with two parameters with the Resource object. First parameter nm is a string by default. The second parameter age uses 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 响应对象的默认内容类型。
Note that the on_get() responder uses the path parameters to form a dict object – retvalue. Its JSON representation is then assigned as the value of response body and returned to the client. As mentioned earlier, JSON is the default content type of Falcon’s response object.
启动 Waitress 服务器,并使用 HTTPie 帮助检查 URL http://localhost:8000/hello/Priya/21 的响应。
Start the Waitress server and check the response for the URL http://localhost:8000/hello/Priya/21 with the help of HTTPie.
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"
}
你还可以使用浏览器中查看响应,如下所示 −
You can also check the response in a browser as follows −

Python Falcon - Suffixed Responders
为了理解概念和后缀响应者的需求,让我们定义一个 StudentResource 类。它包含一个 on_get() 响应者,它将学生列表转换 dict 对象为 JSON 并返回作为其响应。
To understand the concept and the need of suffixed responders, let us define a StudentResource class. It consists of an on_get() responder that converts the students a list of dict objects to JSON and returns as its response.
我们还添加 on_post() 响应器,它从传入请求中读取数据并在列表中添加一个新的 dict 对象。
Let us also add on_post() responder that reads the data from the incoming request and adds a new dict object in the list.
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‘s App 对象的 add_route() 函数,我们添加 /students 路由。
Using add_route() function of the Falcon’s App object, we add /students route.
app = falcon.App()
app.add_route("/students", StudentResource())
在启动服务器后,我们可以从 HTTPie 命令行测试 GET 和 POST 请求 -
After starting the server, we can test the GET and POST requests from HTTPie command line −
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() 来确认添加了新的学生资源。
Invoking on_get() again confirms the addition of new students resource.
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 对象。
At this stage, we would like to have a GET responder method in StudentResource class that reads the id parameter from the URL and retrieves a corresponding dict object of from the list.
换句话说,格式为 /student/{id} 的 URL 应当与资源类中的 GET 方法相关联。但显然,一个类不能有两个相同名称的方法。因此,我们定义对 add_route() 方法使用 suffix 参数来区分 on_get() 响应器的两个定义。
In other words, the URL of the format /student/{id} should be associated to the GET method in the resource class. But obviously, a class cannot have two methods of same name. Hence, we define to use suffix parameter for the add_route() method to distinguish between the two definitions of on_get() responders.
通过指定 suffix ='student' ,将一个带有 id 参数的路由添加到 Application 对象。
A route with id parameter is added to the Application object by specifying suffix ='student'.
app.add_route("/students/{id:int}", StudentResource(), suffix='student')
我们现在可以添加 on_get() 方法的另一个定义和此后缀,以便此响应器的名称为 on_get_student() 如下 -
We can now add another definition of on_get() method with this suffix, so that the name of this responder is on_get_student(), as follows −
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 -
Start the Waitress server after adding the new route and on_get_student() responder and test this URL as follows −
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() 响应器(用于删除资源)也将被调用。
Note that the on_put() responder (to update a resource) and on_delete() responder (to delete a resource) will also get invoked when the URL route /students/{id:int} is requested by the client with appropriate request header.
我们已经添加了此路由,学生作为后缀。因此, on_put_student() 方法将路径参数解析为整数变量。给定 id 的项目的 JSON 表示形式被获取并使用 PUT 请求中提供的数据进行更新。
We have already added this route with student as the suffix. Hence, on_put_student() method parses the path parameter in an integer variable. The JSON representation of the item with given id is fetched and updated with the data provided in the PUT request.
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 的项目。返回剩余资源的列表。
The on_delete_student() responder simply deletes the item with the id specified in the DELETE request. The list of remaining resources is returned.
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 操作 -
We can test the PUT and DELETE operations of the API with HTTPie commands −
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 ) 的完整代码如下 -
The complete code of this API (studentapi.py) is as under −
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 - Inspect Module
inspect 模块是一个方便的工具,它提供有关注册路由和其他 Falcon 应用程序组件(例如中间件、吸收器等)的信息。
The inspect module is a handy tool that provides information about registered routes and other components of a Falcon application such as middleware, sinks etc.
可以通过两种方式检查应用程序 - CLI 工具和以编程方式。从命令行执行 falcon-inspect -tool CLI 脚本,其中给出了申报 Falcon 应用程序对象的 Python 脚本的名称。
The inspection of an application can be done by two ways – CLI tool and programmatically. The falcon-inspect-tool CLI script is executed from the command line giving the name of Python script in which Falcon application object is declared.
例如,如要检查 studentapi.py 中的应用程序对象 -
For example, to inspect application object in 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 模块中的 inspect_app() 函数将应用程序对象作为参数。
The output shows registered routes and the responder methods in the resource class. To perform the inspection programmatically, use the application object as argument to inspect_app() function in the inspect module.
from falcon import inspect
from studentapi import app
app_info = inspect.inspect_app(app)
print(app_info)
将上述脚本另存为 inspectapi.py,然后从命令行运行它。
Save the above script as inspectapi.py and run it from the command line.
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 Template
Falcon 库主要用于构建 API 和微服务。因此,默认情况下,Falcon 响应器返回 JSON 响应。但是,如果将内容类型更改为 falcon.MEDIA_HTML, ,则可以呈现 HTML 输出。
The Falcon library is primarily used to build APIs and microservices. Hence, by default, a Falcon responder returns a JSON response. However, if the content type is changed to falcon.MEDIA_HTML, it is possible to render HTML output.
使用变量数据呈现 HTML 内容非常繁琐。为此,需要使用网络模板库。许多 Python Web 框架都捆绑了特定的模板库。但 Falcon 是一个极简主义微框架,不会捆绑任何模版库。
Rendering a HTML content with variable data is very tedious. For this purpose, web templating libraries are used. Many Python web frameworks are bundled with specific template library. But Falcon being a minimalist micro framework doesn’t come pre-bundled with anyone.
Jinja2 是许多 Python 框架使用的一个最流行的模板库。在本节中,我们将看到如何在 Falcon 应用中使用 inja2。jinja2 是一种快速且对设计人员友好的模板语言,易于配置和调试。它的沙盒环境便于阻止执行不可信代码、禁止潜在不安全数据,并防止跨站点脚本攻击(称为 XSS attacks )。
Jinja2 is one of the most popular template libraries used by many python frameworks. In this section, we shall see how to use inja2 with Falcon application. The jinja2 is a fast and designer-friendly templating language that is easy to configure and debug. Its sandboxed environment makes it easy to prevent the execution of untrusted code, prohibit potentially unsafe data, and prevent cross-site scripting attacks (called XSS attacks).
jinja2 的另一个非常强大的功能是 template inheritance ,其中您可以定义一个具有通用设计功能的基本模板,而子模板可以覆盖该基本模板。
Another very powerful feature of jinja2 is the template inheritance, wherein You can define a base template having common design features which child templates can override.
首先,使用 PIP 实用程序在当前 Python 环境中安装 jinja2 。
First of all, install jinja2 in the current Python environment with the use of PIP utility.
pip3 install jinja2
Hello World Template
jinja2 模块定义了 Template 类。Template 对象是通过读取包含 HTML 脚本(带 .html 扩展名)的文件内容来获取的。通过调用这个 Template 对象的 render() 方法,可以向客户端浏览器呈现 HTML 响应。Response 对象的 content_type 属性必须设置为 falcon.MEDIA_HTML 。
The jinja2 module defines a Template class. A Template object is obtained by reading the contents of a file containing HTML script (one with .html extension). By invoking the render() method of this Template object, HTML response can be rendered to the client browser. The content_type property of Response object must be set to falcon.MEDIA_HTML.
让我们将以下 HTML 脚本另存为 hello.py 放置在应用文件夹中。
Let us save the following HTML script as hello.py in the application folder.
<html>
<body>
<h2>Hello World</h2>
</body>
</html>
Example
下面的资源类中的 on_get() 响应器读取这个文件并将其呈现为 HTML 响应。
The on_get() responder in the resource class below reads this file and renders it as HTML response.
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)
Output
运行以上 Python 代码并访问浏览器中的 http://localhost:8000/hello 链接。
Run the above Python code and visit http://localhost:8000/hello link in the browser.

Template Variable
jinja2 是一个服务器端模板库。网页通过将 jinja2 模板语言的各种元素作为占位符放置到 HTML 脚本内的适当定界符中来构造为模板。模板引擎读取 HTML 脚本,在服务器上用上下文数据替换占位符,重新组装 HTML 并将其呈现给客户端。
jinja2 is a server-side templating library. The web page is constructed as a template by putting various elements of jinja2 templating language as place-holders within appropriate delimiters inside the HTML script. The template engine reads the HTML script, substitutes the place-holders with context data on the server, reassembles the HTML, and renders it to the client.
Template.render() 函数有一个可选的上下文字典参数。这个字典的关键属性变成模板变量。这有助于呈现响应器在网页中传递的数据。
The Template.render() function has an optional context dictionary parameter. The key attributes of this dictionary become the template variables. This helps in rendering the data passed by the responders in the web page.
Example
在以下示例中,路由 /hello/nm 已使用路径参数 nm 注册了资源对象。 on_get() 响应器将其作为上下文传递给从网页获取的模板对象。
In the following example, the route /hello/nm is registered with the resource object, where nm is the path parameter. The on_get() responder passes it as a context to the template object obtained from a web page.
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 响应。
The hello.html reads the path parameter in a template variable name. It acts as a place holder in the HTML script. It is put in {{ and }} symbols so that its value appears as a HTML response.
<html>
<body>
<h2>Hello {{ name }}</h2>
</body>
</html>
Output
运行 Python 代码并输入 http://localhost:8000/hello/Priya 作为 URL。浏览器将显示以下输出:
Run the Python code and enter http://localhost:8000/hello/Priya as the URL. The browser displays the following output −

Loop in jinja2 Template
如果响应器传递任何 Python 可迭代对象,例如列表、元组或字典,则可以使用其循环构造语法在 jinja2 模板内部遍历其元素。
If the responder passes any Python iterable object such as a list, tuple or a dictionary, its elements can be traversed inside the jinja2 template using its looping construct syntax.
{% for item in collection %}
HTML block
{% endfor %}
在以下示例中, on_get() 响应器向模板 list.html 发送 students 对象,该对象是 dict 对象的列表。它会遍历数据并将其呈现为 HTML 表格。
In the following example, the on_get() responder sends students object which is a list of dict objects, to the template list.html. It in turn traverses the data and renders it as a HTML table.
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 模板。它接收 students 对象作为字典对象列表,并将每个键的值放在表的 <td>..<.td> 元素内部。
list.html is a jinja2 template. It receives the students object as list of dictionary objects and puts the value of each key inside <td>..<.td> element of a table.
<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 路由。学生的列表将在浏览器中呈现。
Visit the /students route in the browser’s address bar. The list of students is rendered in the browser.

HTML Form Template
在此部分,我们将看到 Falcon 如何从 HTML 表单读取数据。让我们将以下 HTML 脚本保存为 myform.html。我们将使用它来获取 Template 对象并呈现它。
In this section, we shall see how Falcon reads the data from HTML form. Let us save the following HTML script as myform.html. We shall use it for obtaining Template object and render it.
<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 路由。
The Falcon App object is declared in Hello.py file which also has a resource class mapped to /adddnew route. The on_get() responder reads the myform.html and renders the same. The HTML form will be displayed. The form is submitted to /students route by POST method.
要能够读取表单数据,必须将 auto_parse_form_urlencoded 类的 falcon.RequestOptions 属性设置为 True。
To be able to read the form data, the auto_parse_form_urlencoded property of falcon.RequestOptions class must be set to True.
app = falcon.App()
app.req_options.auto_parse_form_urlencoded = True
此处,我们还从 student.py 中导入 StudentResource 类。 on_get() 响应器呈现学生列表。
Here, we also import StudentResource class from student.py. The on_get() responder renders the list of students.
当用户填写并提交表单时,将调用 on_post() 响应器。此方法收集表单数据到 req.params 属性中,它只不过是一个表单元素及其值的字典。然后附加 students 字典。
The on_post() responder will be called when the user fills and submits the form. This method collects the form data in the req.params property, which is nothing but a dictionary of form elements and their values. The students dictionary is then appended.
def on_post(self, req, resp):
student=req.params
students.append(student)
hello.py 的完整代码如下 −
The complete code of hello.py is as follows −
import falcon
import json
from waitress import serve
from jinja2 import Template
from student import StudentResource
class MyResource:
def on_get(self, req, resp):
resp.status = falcon.HTTP_200
resp.content_type = 'text/html'
fp=open("myform.html","r")
tempobj=Template(fp.read())
resp.body=tempobj.render()
app = falcon.App()
app.req_options.auto_parse_form_urlencoded = True
form = MyResource()
app.add_route('/addnew', form)
app.add_route("/students", StudentResource())
if __name__ == '__main__':
serve(app, host='0.0.0.0', port=8000)
具有 StudentResource 类和 on_get() 及 on_post() 响应器的 student.py 如下 −
The student.py having StudentResource class and on_get() and on_post() responders is as follows −
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})
def on_post(self, req, resp):
student = req.params
students.append(student)
resp.text = "Student added successfully."
resp.status = falcon.HTTP_OK
resp.content_type = falcon.MEDIA_JSON
从命令行运行 hello.py 。通过输入 http://locLhost:8000/addnew 在浏览器中打开 HTML 表单。
Run hello.py from the command line. Open the HTML form in the browser by entering http://locLhost:8000/addnew.

将附加 students 数据库字典。访问 /students 路由。你会发现附加了新行。
The students database dictionary will be appended. Visit /students route. You will find a new row appended.

Multipart Forms
为了让用户从本地文件系统选择文件,必须将 HTML 表单的 enctype 属性设置为 multipart/form-data。Falcon 使用 MultipartFormHandler 处理 multipart/form-data 媒体类型,允许其迭代表单中的主体部分。
In order to let the user select files from the local filesystem, the enctype attribute of HTML form must be set to multipart/form-data. Falcon uses MultipartFormHandler to handle the multipart/form-data media type, allowing it to iterate over the body parts in the form.
BodyPart 类具有以下属性 −
The BodyPart class has the following properties −
-
stream − stream wrapper just for the current body part
-
data − body part content bytes
-
content_type would default to text/plain if not specified, as per RFC
-
text − the current body part decoded as text string (only provided it is of type text/plain, None otherwise)
-
media − automatically parsed by media handlers in the same way as req.media
-
name, filename − relevant parts from the Content-Disposition header
-
secure_filename − sanitized filename that could safely be used on the server filesystem.
以下 HTML 脚本 ( index.html ) 是一个多部分表单。
The following HTML script (index.html) is a multi-part form.
<html>
<body>
<form action="http://localhost:8000/hello" method="POST" enctype="multipart/form-data">
<h3>Enter User name</h3>
<p><input type='text' name='name'/></p>
<h3>Enter address</h3>
<p><input type='text' name='addr'/></p>
<p><input type="file" name="file" /></p>
<p><input type='submit' value='submit'/></p>
</form>
</body>
</html>
此表格由下方代码中的 on_get() 响应器渲染。将表格数据提交给 on_post() 方法,该方法将迭代部分并发送表格数据的 JSON 响应。
This form is rendered by the on_get() responder of the HelloResource class in the code below. The form data is submitted to on_post() method which iterates over the parts and sends a JSON response of the form data.
import waitress
import falcon
import json
from jinja2 import Template
class HelloResource:
def on_get(self, req, resp):
resp.status = falcon.HTTP_200
resp.content_type = 'text/html'
fp=open("index.html","r")
tempobj=Template(fp.read())
resp.body=tempobj.render()
def on_post(self, req, resp):
result=[]
for part in req.media:
data={"name" :part.name,
"content type":part.content_type,
"value":part.text, "file":part.filename}
result.append(data)
resp.text = json.dumps(result)
resp.status = falcon.HTTP_OK
resp.content_type = falcon.MEDIA_JSON
app = falcon.App()
hello = HelloResource()
app.add_route('/hello', hello)
if __name__ == '__main__':
waitress.serve(app, host='0.0.0.0', port=8000)
运行以上程序并访问 http://localhost:8000/hello 链接,如以下所示,以渲染表格 -
Run the above program and visit http://localhost:8000/hello link to render the form as shown below −

当在填写数据后提交表格时,将在浏览器中显示 JSON 响应,如下所示:
When the form is submitted after filling the data, the JSON response is rendered in the browser as shown below −
[
{
"name": "name",
"content type": "text/plain",
"value": "SuyashKumar Khanna",
"file": null
},
{
"name": "addr",
"content type": "text/plain",
"value": "New Delhi",
"file": null
},
{
"name": "file",
"content type": "image/png",
"value": null,
"file": "hello.png"
}
]
Python Falcon - Cookies
Cookie 以文本文件形式存储在客户端计算机上。其目的是记住并跟踪与客户端使用相关的数据,以便提供更好的访问者体验和网站统计信息。
A cookie is stored on a client’s computer in the form of a text file. Its purpose is to remember and track data pertaining to a client’s usage for better visitor experience and site statistics.
请求对象包含 Cookie 的属性。它是客户端已传输的所有 Cookie 变量及其相应值的字典对象。此外,Cookie 还存储其过期时间、路径和网站的域名。
A Request object contains a cookie’s attribute. It is a dictionary object of all the cookie variables and their corresponding values, a client has transmitted. In addition to it, a cookie also stores its expiry time, path and domain name of the site.
在 Falcon 中,使用 set_cookie() 方法在响应对象上设置 Cookie。
In Falcon, cookies are set on response object using set_cookie() method.
resp.set_cookie('cookiename', 'cookievalue')
此外,Cookie 的参数 max_age (以秒为单位)和域名也可以给出。
Additionally, the arguments max_age of cookie in seconds and domain name can also be given.
import falcon
import json
from waitress import serve
class resource1:
def on_post(self, req, resp):
resp.set_cookie("user", 'admin')
resp.text = "cookie set successfully."
resp.status = falcon.HTTP_OK
resp.content_type = falcon.MEDIA_TEXT
从命令行调用响应器方法,如下所示:
From the command line, invoke the responder method as −
http POST localhost:8000/cookie
HTTP/1.1 200 OK
Content-Length: 24
Content-Type: text/plain; charset=utf-8
Date: Tue, 26 Apr 2022 06:56:30 GMT
Server: waitress
Set-Cookie: user=admin; HttpOnly; Secure
cookie set successfully.
也可以使用响应对象的 append_header() 方法设置 Cookie Set-cookie 头。
The cookie Set-cookie header can also be set using append_header() method of response object.
要检索 Cookie,请求对象具有 request.cookies 属性以及 get_cookie_values() 方法。
To retrieve the cookies, the request object has request.cookies property as well as get_cookie_values() method.
def on_get(self, req, resp):
cookies=req.cookies
values = req.get_cookie_values('user')
if values:
v = values[0]
resp.body={"user":v}
resp.status = falcon.HTTP_OK
resp.content_type = falcon.MEDIA_JSON
响应对象的 unset_cookie 方法用于清除当前请求的 Cookie。
The unset_cookie method of response object clears the cookie for the current request.
resp.unset_cookie('user')
对于 ASGI 应用程序, falcon.asgi.Request 与 falcon.Request 实现了相同的 Cookie 方法和属性。 set_cookie() 和 append_header() 的 ASGI 版本是同步的,因此不需要等候。
For ASGI applications, falcon.asgi.Request implements the same cookie methods and properties as falcon.Request. The ASGI versions of set_cookie() and append_header() are synchronous, so they do not need to be awaited.
Python Falcon - Status Codes
默认情况下,HTTP 服务器对客户端请求的响应具有 200 OK 状态。Falcon 提供了自己的状态常量列表,以提高便利性和可读性。
By default, the HTTP server’s response to a client’s request is having 200 OK status. Falcon provides its own list of status constant for more convenience and readability.
例如,200 OK 状态代码表示为:
For example, 200 OK status code is represented by,
resp.status = falcon.HTTP_OK
这些预定义的 Falcon 常量避免了输入错误,并减少了准备响应时必须创建的字符串对象数量。然而,从 Falcon 3.0 版本开始,允许使用 int 代码。
These predefined Falcon constants avoid typos and cuts down on the number of string objects that must be created when preparing responses. However, starting with Falcon version 3.0, using bare int codes is allowed as well.
resp.status = 200
对于 ASGI 应用程序,相同的状态代码适用。
For ASGI application, same status codes are applicable.
Falcon 库中定义的部分状态代码如下:
Some of the status codes defined in Falcon library are listed below −
Informational Codes
-
HTTP_CONTINUE = HTTP_100
-
HTTP_SWITCHING_PROTOCOLS = HTTP_101
-
HTTP_PROCESSING = HTTP_102
Success Status Codes
-
HTTP_OK = HTTP_200
-
HTTP_CREATED = HTTP_201
-
HTTP_ACCEPTED = HTTP_202
-
HTTP_NON_AUTHORITATIVE_INFORMATION = HTTP_203
-
HTTP_NO_CONTENT = HTTP_204
-
HTTP_RESET_CONTENT = HTTP_205
-
HTTP_PARTIAL_CONTENT = HTTP_206
-
HTTP_MULTI_STATUS = HTTP_207
-
HTTP_ALREADY_REPORTED = HTTP_208
-
HTTP_IM_USED = HTTP_226
Redirection Error Codes
-
HTTP_MULTIPLE_CHOICES = HTTP_300
-
HTTP_MOVED_PERMANENTLY = HTTP_301
-
HTTP_FOUND = HTTP_302
-
HTTP_SEE_OTHER = HTTP_303
-
HTTP_NOT_MODIFIED = HTTP_304
-
HTTP_USE_PROXY = HTTP_305
-
HTTP_TEMPORARY_REDIRECT = HTTP_307
-
HTTP_PERMANENT_REDIRECT = HTTP_308
Client Error Codes
-
HTTP_BAD_REQUEST = HTTP_400
-
HTTP_UNAUTHORIZED = HTTP_401 # "unauthenticated"
-
HTTP_PAYMENT_REQUIRED = HTTP_402
-
HTTP_FORBIDDEN = HTTP_403 # "unauthorized"
-
HTTP_NOT_FOUND = HTTP_404
-
HTTP_METHOD_NOT_ALLOWED = HTTP_405
-
HTTP_NOT_ACCEPTABLE = HTTP_406
-
HTTP_PROXY_AUTHENTICATION_REQUIRED = HTTP_407
-
HTTP_REQUEST_TIMEOUT = HTTP_408
-
HTTP_CONFLICT = HTTP_409
Server Error Codes
-
HTTP_INTERNAL_SERVER_ERROR = HTTP_500
-
HTTP_NOT_IMPLEMENTED = HTTP_501
-
HTTP_BAD_GATEWAY = HTTP_502
-
HTTP_SERVICE_UNAVAILABLE = HTTP_503
-
HTTP_GATEWAY_TIMEOUT = HTTP_504
-
HTTP_HTTP_VERSION_NOT_SUPPORTED = HTTP_505
-
HTTP_INSUFFICIENT_STORAGE = HTTP_507
-
HTTP_LOOP_DETECTED = HTTP_508
-
HTTP_NETWORK_AUTHENTICATION_REQUIRED = HTTP_511
Python Falcon - Error Handling
为了处理各种错误情况,上述状态代码可用于响应对象。Falcon 还提供了一组错误类。当出现相应的运行时错误情况时,可以引发其对象。
To handle various error situations, the above status codes can be used for the response object. Falcon also provides set of error classes. Their object can be raised when corresponding runtime error situation arises.
这些错误类源自 HTTPError 类作为其基类。错误对象会引发,如下例所示−
These error classes are derived from HTTPError class as their base class. The error object is raised as shown in the following example −
import falcon
class MyResource:
def on_get(self, req, resp):
# some Python code
raise falcon.HTTPBadRequest(
title="Value Out of Range",
description="The value is not between permissible range"
)
Predefined Error Classes
Falcon 提供的一些预定义错误类如下−
Some of the predefined error classes provided by Falcon are as follows −
-
HTTPBadRequest − 400 Bad Request. The server is unable to process the request due to a client error such as malformed request syntax, invalid request message framing etc.
-
HTTPInvalidHeader − Results in 400 Bad Request because one of the headers in the request is invalid.
-
HTTPInvalidParam − Represents 400 Bad Request. This error may refer to an invalid parameter in a query string, form, or document that was submitted with the request.
-
HTTPMissingParam − 00 Bad Request is raised when a parameter is missing from the request.
-
HTTPForbidden − The server understood the request but refuses to authorize it. The status code is 403 Forbidden.
-
HTTPNotFound − When the server did not find a current representation for the target resource, a 404 status code is raised. It does not indicate whether this lack of representation is temporary or permanent.
-
HTTPMethodNotAllowed − 405 Method Not Allowed. The method received in the request-line is not supported by the target resource.
-
HTTPLengthRequired − When The server refuses to accept the request without a defined Content- Length. 411 Length Required. Error code.
-
HTTPUnsupportedMediaType − If the origin server is refusing to service the request because the payload is in a format not supported by this method on the target resource. Equivalent status code is 415 Unsupported Media Type.
-
HTTPUnprocessableEntity − If the server understands the content type of the request entity and the syntax of the request entity is correct but was unable to process the contained instructions, the error status code raised is 422 Unprocessable Entity. For example, if an XML request body contains well-formed, but semantically erroneous, XML instructions.
-
HTTPTooManyRequests − A 429 Too Many Requests status code is raised when the user has sent too many requests in a given amount of time (“rate limiting”).
-
HTTPInternalServerError − A very common error situation resulting in 500 Internal Server Error. The server encountered an unexpected condition that prevented it from fulfilling the request.
-
HTTPNotImplemented − The 501 (Not Implemented) status code indicates that the server does not support the functionality required to fulfill the request. This is the appropriate response when the server does not recognize the request method and is not capable of supporting it for any resource.
-
HTTPServiceUnavailable − 503 Service Unavailable means that the server is currently unable to handle the request due to a temporary overload or scheduled maintenance.
-
MediaNotFoundError − 400 Bad Request. This Exception is raised by a media handler when trying to parse an empty body.
-
MediaMalformedError − 400 Bad Request. This Exception is raised by a media handler when trying to parse a malformed body.
Redirection
也有一组例外,当引发这些异常时,会触发对客户端的重定向响应。状态代码属于 3xx 类型。由以下类表示的这些异常作为 HttpError 的子类来短路请求处理。
There are also a set of exceptions, which when raised, trigger a redirection response to the client. The status codes are of the type 3xx. These exceptions, represented by following classes, shot-circuit the request processing as a subclass of HttpError.
-
HTTPMovedPermanently − 301 Moved Permanently. This status code indicates that the target resource has been assigned a new permanent URI.
-
HTTPFound − 302 Found status code meaning that the target resource resides temporarily under a different URI.
-
HTTPTemporaryRedirect − This class raises the 307 (Temporary Redirect) status code, which means that the target resource resides temporarily under a different URI and the user agent MUST NOT change the request method if it performs an automatic redirection to that URI.
-
HTTPPermanentRedirect − Results ib 308 Permanent Redirect, indicating that the target resource has been assigned a new permanent URI.
Python Falcon - Hooks
钩子是在响应客户端请求时在资源类中的特定响应程序方法被调用时自动执行的用户定义函数。Falcon 支持 before 和 after 钩子。
Hooks are the user defined functions that are executed automatically when a specific responder method in the resource class is invoked in response to the client request. Falcon supports before and after hooks.
作为钩子使用的函数被定义为具有请求、响应和资源类的参数,除了可能需要的任何可选参数。
A function to be used as a hook is defined with the request, response and resource class as parameters, in additional to any optional parameters as may be necessary.
def hookfunction(req, resp, resource):
. . . . .
. . . . .
此类函数通过应用以下装饰器之一附加到单个响应程序或整个资源类 -
Such a function is attached to either an individual responder or the entire resource class by applying one of the following decorators −
-
@falcon.before(hookfunction)
-
@falcon.after(hookfunction)
将 before 钩子应用于 on_post() 响应程序 -
To apply the before hook to the on_post() responder −
@falcon.before(hookfunction)
def on_post(self, req, resp):
. . .
. . .
应用一个 after 钩子 -
To apply an after hook −
@falcon.after(hookfunction)
def on_get(self, req, resp):
. . .
. . .
要装饰整个资源类,请在类声明上方使用装饰器 -
To decorate the entire resource class, use the decorator above the declaration of the class −
@falcon.after(hookfunction)
class SomeResource:
def on_get(self, req, resp):
. . .
. . .
def on_post(self, req, resp):
. . .
. . .
在以下示例中,我们有 StudentResource 类,其中已定义 on_get() 和 on_post() 响应程序。当 POST 请求发送一些数据并且使用它创建的新 dict 对象被添加到 Students 列表中时,会调用 on_post() 响应程序。
In the following example, we have the StudentResource class in which on_get() and on_post() responders have been defined. The on_post() responder is invoked when a POST request sends some data and a new dict object created with it is added in the Students list.
接收到的数据需要在处理之前进行验证。为此,已定义以下函数。它检查 percent 参数的值是否在 0 和 100 之间。仅当数据通过此条件时,才将其传递给响应程序。
The data received needs to be validated before processing. For this purpose, the following function has been defined. It checks whether value of percent parameter is between 0 and 100. Only if the data passes this condition, it is passed to the responder.
def checkinput(req, resp, resource,params):
student = json.load(req.bounded_stream)
if "name" not in student:
raise falcon.HTTPBadRequest(
title="Bad request", description="Bad input, name must be provided."
)
per=int(student['percent'])
if per<0 or per>100:
raise falcon.HTTPBadRequest(
title="Bad request", description="Bad input, invalid percentage"
)
req.context.data = student
此函数作为 StudentResource 类的 on_post() 响应程序上的钩子应用。
This function is applied as a hook on the on_post() responder of the StudentResource class.
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
@falcon.before(checkinput)
def on_post(self, req, resp):
student = json.load(req.context.data)
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
app = falcon.App()
app.add_route("/students", StudentResource())
if __name__ == '__main__':
serve(app, host='0.0.0.0', port=8000)
让我们运行 Waitress 服务器并发起 POST 请求。
Let us run the Waitress server and initiate the POST request.
http POST localhost:8000/students id=4 percent=50
HTTP/1.1 400 Bad Request
Content-Length: 76
Content-Type: application/json
Date: Tue, 26 Apr 2022 14:49:07 GMT
Server: waitress
Vary: Accept {
"description": "Bad input, name must be provided.",
"title": "Bad request"
}
由于数据不包含 name 参数的值,因此引发异常。
Since the data doesn’t contain value of name parameter, the exception is raised.
在下面显示的另一个 POST 请求中,percent 参数的值未满足所需条件,因此会引发异常。
In another POST request as shown below, the value of percent parameter fails to meet the required criteria, hence the exception.
http POST localhost:8000/students id=4 name="aaa" percent=500
HTTP/1.1 400 Bad Request
Content-Length: 72
Content-Type: application/json
Date: Tue, 26 Apr 2022 15:01:20 GMT
Server: waitress
Vary: Accept {
"description": "Bad input, invalid percentage",
"title": "Bad request"
}
Python Falcon - Middleware
"middleware" 是一个函数,用它来处理每个请求(在由任何特定响应程序处理之前),以及在返回每个响应之前。此函数会处理发送到应用程序的每个请求。
A "middleware" is a function that is processed with every request (before being processed by any specific responder) as well as with every response before returning it. This function takes each request that comes to your application.
中间件的作用类似于 hook。但是,与 hook 不同,中间件方法全局应用于整个应用程序。它可以通过运行其中定义的代码对请求执行某些流程,然后将请求传递给相应的操作函数进行处理。它还可以在返回生成的响应之前对其进行处理。
A middleware works similar to hooks. However, unlike hooks, middleware methods apply globally to the entire App. It may perform some process with the request by running a code defined in it, and then passes the request to be processed the corresponding operation function. It can also process the response generated by the operation function before returning it.
中间件是一个类,它实现一个或多个以下事件处理程序方法。对于 WSGI 应用程序,方法为:
A middleware is a class that implements one or more of the following even handler methods. For a WSGI app, the methods are −
-
process_request (self, req, resp) − This method processes the request before routing it.
-
process_resource (self, req, resp, resource, params) − processes the request after routing. A dict object representing any additional params derived from the route’s URI template fields may be passed.
-
process_response (self, req, resp, resource, req_succeeded) − This method is for post-processing of the response (after routing). The req_succeeded parameter is True if no exceptions were raised otherwise False.
对于 ASGI 应用程序,除了上述方法外,中间件类还可以定义更多的方法。
In case of the ASGI app, in addition to the above methods, the middleware class may define some more methods.
为了考虑 ASGI 规范的可选部分寿命事件,可以包括启动和关闭事件处理程序。
To account for lifespan events, an optional part of ASGI specification, the startup and shutdown event handlers may be included.
-
process_startup (self, scope, event) − This method processes the ASGI lifespan startup event. It is invoked when the server is ready to start up and receive connections, but before it has started to do so.
-
process_shutdown(self, scope, event) − This method processes the ASGI lifespan shutdown event. It is invoked when the server has stopped accepting connections and closed all active connections.
由于 ASGI 应用程序还响应 Websocket 协议下的请求,因此中间件可以定义以下协程方法:
Since the ASGI application also responds to the requests under Websocket protocol, the middleware may define following coroutine methods −
-
process_request_ws (self, req, ws) − This method processes a WebSocket handshake request before routing it.
-
process_resource_ws (self, req, ws, resource, params) − This method processes a WebSocket handshake request after routing. A dict object derived from the route’s URI template fields may be passed to the resource’s responder.
中间件类的实例必须在初始化时添加到 Falcon 应用程序对象中。对于 WSGI Falcon 应用程序:
An instance of the middleware class has to be added to the Falcon application object at the time of initialization. For a WSGI Falcon app −
class MyMiddleware:
def process_request(self, req, resp):
pass
def process_resource(self, req, resp, resource, params):
pass
def process_response(self, req, resp, resource, req_succeeded):
pass
from falcon import App
app=App(middleware=[MyMiddleware()])
对于 ASGI 应用程序:
For the ASGI app −
class MyMiddleware:
async def process_startup(self, scope, event):
pass
async def process_shutdown(self, scope, event):
pass
async def process_request(self, req, resp):
pass
async def process_resource(self, req, resp, resource, params):
pass
async def process_response(self, req, resp, resource, req_succeeded):
pass
async def process_request_ws(self, req, ws):
pass
async def process_resource_ws(self, req, ws, resource, params):
pass
from falcon.asgi import App
app=App(middleware=[MyMiddleware()])
Python Falcon - CORS
"Cross-Origin Resource Sharing" (CORS) 是指运行在某个客户端浏览器上的前端应用程序尝试通过 JavaScript 代码与后端通信的情况,并且后端与前端处于不同的“来源”中。这里的来源是协议、域名和端口号的组合。因此, http://localhost 和 https://localhost 有不同的来源。
"Cross-Origin Resource Sharing" (CORS) is a situation when a frontend application that is running on one client browser tries to communicate with a backend through JavaScript code, and the backend is in a different "origin"than the frontend. The origin here is a combination of protocol, domain name and port numbers. As a result, http://localhost and https://localhost have different origins.
如果具有一个来源的 URL 的浏览器发送从另一个来源执行 JavaScript 代码的请求,则浏览器会发送 OPTIONS http 请求。如果后端通过发送适当的标头授权来自此其他来源的通信,它将允许前端的 JavaScript 将其请求发送到后端。
If the browser with URL of one origin sends request for execution of JavaScript code from another origin, the browser sends OPTIONS http request. If the backend authorizes the communication from this different origin by sending the appropriate headers it will let the JavaScript in the frontend send its request to the backend.
若要为所有响应启用 CORS 策略,则应将 Falcon 应用配置如下所示:
To enable the CORS policy for all responses, the Falcon app is configured as follows −
from falcon import App
app=App(cors_enable=True)
若要明确指定允许的源,请导入 CORSMiddleware ,并将源列表添加到应用中间件中,同时附带各自的凭据。
To specify explicitly the allowed origins, import CORSMiddleware and add the list of origins to the app’s middleware, along with respective credentials.
from falcon import App
app = falcon.App(middleware=falcon.CORSMiddleware(allow_origins='example.com', allow_credentials='*')
Python Falcon - Websocket
WebSocket 是客户端与服务器之间的持久连接,可在这两者之间提供双向 full-duplex 通信。通信经由 HTTP 在单个 TCP/IP 套接字连接中发生。这可以看做是 HTTP 的升级,而不是一个协议本身。
A WebSocket is a persistent connection between a client and server to provide a bidirectional, full-duplex communication between the two. The communication takes place over HTTP through a single TCP/IP socket connection. It can be seen as an upgrade of HTTP instead of a protocol itself.
HTTP 的局限性之一是它是一个严格的半双工或单向协议。另一方面,借助 WebSocket,我们可以发送基于消息的数据(类似于 UDP),但借助 TCP 的可靠性。WebSocket 使用 HTTP 作为初始传输机制,但在收到 HTTP 响应后保持 TCP 连接的活动状态。可以将同一连接对象用于客户端和服务器之间的双向通信。因此,可以使用 WebSocket API 构建实时应用。
One of the limitations of HTTP is that it is a strictly half-duplex or unidirectional protocol. With WebSockets, on the other hand, we can send message-based data, similar to UDP, but with the reliability of TCP. WebSocket uses HTTP as the initial transport mechanism, but keeps the TCP connection alive the connection after the HTTP response is received. Same connection object it can be used two-way communication between client and server. Thus, real-time applications can be built using WebSocket APIs.
Falcon 的 Websocket 支持仅适用于 ASGI 应用。若要提供 Websocket 能力,资源类应具有 on_websocket() 回应器协程。
Falcon’s Websocket support is available only for ASGI applications. To provide Websocket capability, the resource class should have on_websocket() responder coroutine.
async def on_websocket(self, req, ws):
. . .
Websocket 请求还可由钩子和中间件拦截。将传递 falcon.asgi.WebSocket 对象,而不是 Response 对象。
Websocket requests can also be intercepted by hooks and middleware. Instead of the Response object, a falcon.asgi.WebSocket object is passed.
How Does a WebSocket Function in Falcon?
以下示例演示了 Falcon 应用中 WebSocket 的功能。首先,我们有一个 on_get() 回应器,它用来呈现一个模板。
The following example demonstrates the functioning of WebSocket in Falcon application. First we have an on_get() responder that renders a template.
Example
客户端浏览器显示一个带有文本字段和按钮的表单,单击该按钮时,就会创建一个 websocket 对象,并触发 on_websocket() 回应器。它接受用户输入的消息,并以“消息文本为”为前缀将它反馈给客户端。
The client browser displays a form with a text field and a button, When the button is clicked, a websocket object is created, and the on_websocket() responder is fired. It accepts the message input by the user and echoes it back to the client with a prefix “The message text was”.
import falcon
import falcon.asgi
import jinja2
html = """
<!DOCTYPE html>
<html>
<head>
<title>Chat</title>
</head>
<body>
<script>
var ws = new WebSocket("ws://localhost:8000/hello");
ws.onmessage = function(event) {
var messages =document.getElementById('messages')
var message = document.createElement('li')
var content = document.createTextNode(event.data)
message.appendChild(content)
messages.appendChild(message)
};
function sendMessage(event) {
var input = document.getElementById("messageText")
ws.send(input.value)
input.value = ''
event.preventDefault()
}
</script>
<h1>WebSocket Chat</h1>
<form action="" onsubmit="sendMessage(event)">
<input type="text" id="messageText" autocomplete="off"/>
<button>Send</button>
</form>
<ul id='messages'></ul>
</body>
</html>
"""
class HelloResource:
async def on_get(self, req, resp):
"""Handles GET requests"""
resp.status = falcon.HTTP_200
resp.content_type = 'text/html'
template=jinja2.Template(html)
resp.body=template.render()
async def on_websocket(self, req, websocket):
await websocket.accept()
while True:
data = await websocket.receive_text()
await websocket.send_text(f"Message text was: {data}")
app = falcon.asgi.App()
hello = HelloResource()
app.add_route('/hello', hello)
import uvicorn
if __name__ == "__main__":
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
Output
启动 Uvicorn 服务器,并访问 http://localhost:8000/ws URL 以显示聊天表单。
Start the Uvicorn server and visit http://localhost:8000/ws URL to display the chat form.

输入一些文本并按 Send 按钮。
Enter some text and press the Send button.

Python Falcon - SQLAlchemy Models
若要演示 Falcon 的响应器如何发挥作用 ( on_post(), on_get(), on_put() 和 on_delete() ),我们对 Python 词典对象的列表形式的内存数据库执行了 CRUD (表示创建、检索、更新和删除)操作。相反,我们可以使用任何关系数据库(例如 MySQL、Oracle 等)来执行存储、检索、更新和删除操作。
To demonstrate how the Falcon’s responder functions (on_post(), on_get(), on_put() and on_delete()), we had done CRUD (which stands for Create, Retrieve, Update and Delete) operations on an in-memory database in the form of a Python list of dictionary objects. Instead, we can use any relational database (such as MySQL, Oracle etc.) to perform store, retrieve, update and delete operations.
我们不会使用 DB-API 合规的数据库驱动程序,而会使用 SQLAlchemy 作为 Python 代码和数据库之间的界面(我们将使用 SQLite 数据库,因为 Python 已内置对它的支持)。SQLAlchemy 是一个流行的 SQL 工具包和 Object Relational Mapper 。
Instead of using a DB-API compliant database driver, we shall use SQLAlchemy as an interface between Python code and a database (we are going to use SQLite database as Python has in-built support for it). SQLAlchemy is a popular SQL toolkit and Object Relational Mapper.
对象关系映射是一种编程技术,用于在面向对象编程语言的不同类型系统之间转换数据。通常,像 Python 这种面向对象语言中使用的类型系统包含非标量类型。但是,大多数数据库产品的(例如 Oracle、MySQL 等)数据类型都是基本类型,例如整数和字符串。
Object Relational Mapping is a programming technique for converting data between incompatible type systems in object-oriented programming languages. Usually, the type system used in an Object Oriented language like Python contains non-scalar types. However, data types in most of the database products such as Oracle, MySQL, etc., are of primitive types such as integers and strings.
在 ORM 系统中,每个类都映射到底层数据库中的一个表。ORM 负责处理这些问题,让你专注于对系统逻辑进行编程,而不再需要自己编写乏味的数据库接口代码。
In an ORM system, each class maps to a table in the underlying database. Instead of writing tedious database interfacing code yourself, an ORM takes care of these issues for you while you can focus on programming the logics of the system.
为了使用 SQLALchemy,我们需要先使用 PIP 安装程序来安装该库。
In order to use SQLALchemy, we need to first install the library using PIP installer.
pip install sqlalchemy
SQLAlchemy 被设计为使用专为某个特定数据库而构建的 DBAPI 实现来运行。它使用方言系统与各种类型的 DBAPI 实现和数据库通信。所有方言都要求已安装相应的 DBAPI 驱动程序。
SQLAlchemy is designed to operate with a DBAPI implementation built for a particular database. It uses dialect system to communicate with various types of DBAPI implementations and databases. All dialects require that an appropriate DBAPI driver is installed.
以下是包含的方言:
The following are the dialects included −
-
Firebird
-
Microsoft SQL Server
-
MySQL
-
Oracle
-
PostgreSQL
-
SQLite
-
Sybase
Database Engine
由于我们打算使用 SQLite 数据库,因此需要为名为 test.db 的数据库创建一个数据库引擎。从 sqlalchemy 模块中导入 create_engine() 函数。
Since we are going to use SQLite database, we need to create a database engine for our database called test.db. Import create_engine() function from sqlalchemy module.
from sqlalchemy import create_engine
from sqlalchemy.dialects.sqlite import *
SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args =
{"check_same_thread": False})
为了与数据库交互,我们需要获取它的句柄。会话对象是数据库的句柄。会话类使用 sessionmaker() 定义,一个可配置的会话工厂方法,它绑定到引擎对象。
In order to interact with the database, we need to obtain its handle. A session object is the handle to database. Session class is defined using sessionmaker() – a configurable session factory method which is bound to the engine object.
from sqlalchemy.orm import sessionmaker, Session
session = sessionmaker(autocommit=False, autoflush=False, bind=engine)
接下来,我们需要一个声明式基类,用于在声明式系统中存储类的目录和映射的表。
Next, we need a declarative base class that stores a catalog of classes and mapped tables in the Declarative system.
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
Model class
Students 是 Base 的子类,映射到了数据库中的 students 表。Books 类中的属性对应于目标表中列的数据类型。请注意,id 属性对应于 book 表中的主键。
Students, a subclass of Base is mapped to a students table in the database. Attributes in the Books class correspond to the data types of the columns in the target table. Note that the id attribute corresponds to the primary key in the book table.
class Students(Base):
__tablename__ = 'student'
id = Column(Integer, primary_key=True, nullable=False)
name = Column(String(63), unique=True)
marks = Column(Integer)
Base.metadata.create_all(bind=engine)
create_all() 方法创建了数据库中对应的表。可以通过使用像 SQLiteStudio 这样的 SQLite 视觉工具来确认。
The create_all() method creates the corresponding tables in the database. It can be confirmed by using a SQLite Visual tool such as SQLiteStudio.

我们现在需要声明一个 StudentResource 类,其中定义了 HTTP 响应者方法,用于对学生表执行 CRUD 操作。此类的对象与路由关联,如下图段所示:
We now need to declare a StudentResource class in which the HTTP responder methods are defined to perform CRUD operations on students table. The object of this class is associated to routes as shown in the following snippet −
import falcon
import json
from waitress import serve
class StudentResource:
def on_get(self, req, resp):
pass
def on_post(self, req, resp):
pass
def on_put_student(self, req, resp, id):
pass
def on_delete_student(self, req, resp, id):
pass
app = falcon.App()
app.add_route("/students", StudentResource())
app.add_route("/students/{id:int}", StudentResource(), suffix='student')
on_post()
其余代码与内存中 CRUD 操作类似,不同之处在于操作函数通过 SQLalchemy 接口与数据库进行交互。
Rest of the code is just similar to in-memory CRUD operations, with the difference being the operation functions interact with the database through SQLalchemy interface.
on_post() 响应者方法首先根据请求参数构造 Students 类的对象,并将其添加到 Students 模型中。由于此模型映射到了数据库中的 students 表,因此会添加相应的行。 on_post() 方法如下:
The on_post() responder method first constructs an object of Students class from the request parameters and adds it the Students model. Since this model is mapped to the students table in the database, corresponding row is added. The on_post() method is as follows −
def on_post(self, req, resp):
data = json.load(req.bounded_stream)
student=Students(id=data['id'], name=data['name'], marks=data['marks'])
session.add(student)
session.commit()
resp.text = "Student added successfully."
resp.status = falcon.HTTP_OK
resp.content_type = falcon.MEDIA_TEXT
如前所述,当收到 POST 请求时,会调用 on_post() 响应者。我们将使用 Postman 应用来传递 POST 请求。
As mentioned earlier, the on_post() responder is invoked when a POST request is received. We shall use Postman app to pass the POST request.
启动 Postman,选择 POST 方法并传递值 (id=1, name="Manan" and marks=760 作为 body 参数。请求成功处理,并向 students 表中添加一行。
Start Postman, select POST method and pass the values (id=1, name="Manan" and marks=760 as the body parameters. The request is processed successfully and a row is added to the students table.

继续并发送多个 POST 请求以添加记录。
Go ahead and send multiple POST requests to add records.
on_get()
此响应者用于检索 Students 模型中的所有对象。 Session 对象上的 query() 方法检索对象。
This responder is meant to retrieve all the objects in the Students model. query() method on Session object retrieves the objects.
rows = session.query(Students).all()
由于 Falcon 响应者的默认响应采用 JSON 格式,因此我们必须将上述查询的结果转换成 dict 对象的列表。
Since the default response of Falcon responder is in JSON format, we have to convert the result of above query in a list of dict objects.
data=[]
for row in rows:
data.append({"id":row.id, "name":row.name, "marks":row.marks})
在 StudentResource 类中,我们添加执行此操作并发送其 JSON 响应的方法 on_get() ,如下所示:
In the StudentResource class, let us add the on_get() method that performs this operation and sends its JSON response as follows −
def on_get(self, req, resp):
rows = session.query(Students).all()
data=[]
for row in rows:
data.append({"id":row.id, "name":row.name, "marks":row.marks})
resp.text = json.dumps(data)
resp.status = falcon.HTTP_OK
resp.content_type = falcon.MEDIA_JSON
可以在 Postman 应用中测试 GET 请求操作。 /students URL 将显示 JSON 响应,显示学生模型中所有对象的数据。
The GET request operation can be tested in the Postman app. The /students URL will result in displaying JSON response showing data of all objects in the students model.

Postman 应用的结果窗格中显示的两条记录也可以在 SQLiteStudio 的数据视图中进行验证。
The two records shown in the result pane of Postman app can also be verified in the data view of SQLiteStudio.

on_put()
on_put() 响应者执行 UPDATE 操作。它响应 URL /students/id 。要从 Students 模型中获取具有给定 id 的对象,我们对查询结果应用过滤器,并使用从客户端接收到的数据更新其属性的值。
The on_put() responder performs the UPDATE operation. It responds to the URL /students/id. To fetch the object with given id from the Students model, we apply the filter to the query result, and update the values of its attributes with the data received from the client.
student = session.query(Students).filter(Students.id == id).first()
on_put() 方法的代码如下:
The on_put() method’s code is as follows −
def on_put_student(self, req, resp, id):
student = session.query(Students).filter(Students.id == id).first()
data = json.load(req.bounded_stream)
student.name=data['name']
student.marks=data['marks']
session.commit()
resp.text = "Student updated successfully."
resp.status = falcon.HTTP_OK
resp.content_type = falcon.MEDIA_TEXT
让我们在 Postman 的帮助下更新 Students 模型中 id 为 id=2 的对象,并更改 name 和 marks。请注意,这些值作为 body 参数传递。
Let us update the object with id=2 in the Students model with the help of Postman and change the name and marks. Note that the values are passed as body parameters.

SQLiteStudio 中的数据视图显示这些修改已经生效。
The data view in SQLiteStudio shows that the modifications have been effected.

on_delete()
最后,DELETE 操作很简单。我们需要获取给定 id 的对象,并调用 delete() 方法。
Lastly, the DELETE operation is easy. We need to fetch the object of the given id and call the delete() method.
def on_delete_student(self, req, resp, id):
try:
session.query(Students).filter(Students.id == id).delete()
session.commit()
except Exception as e:
raise Exception(e)
resp.text = "deleted successfully"
resp.status = falcon.HTTP_OK
resp.content_type = falcon.MEDIA_TEXT
为了测试 on_delete() 应答者,让我们在 Postman 的帮助下删除 id=2 的对象,如下所示 −
As a test of the on_delete() responder, let us delete the object with id=2 with the help of Postman as shown below −

Python Falcon - Testing
Falcon 的测试模块是 Falcon 应用程序的功能测试框架。它包含各种测试类和实用程序函数,以支持功能测试。测试框架同时支持 unittest 和 pytest 。
Falcon’s testing module is a Functional testing framework for Falcon apps. It contains various test classes and utility functions to support functional testing. The testing framework supports both unittest and pytest.
我们将使用以下脚本 ( myapp.py ) 来演示测试功能。它包含一个 HelloResource 类,其中包含一个 on_get() 应答者,该应答者呈现一个 Hello World 的 JSON 响应。 create() 函数返回 Falcon 的 Application 对象,其中添加了一个使用 '/' URL 注册的路由。
We shall use following the script (myapp.py) to demonstrate testing functionality. It contains a HelloResource class with an on_get() responder that renders a JSON response of Hello World. The create() function returns Falcon’s Application object added with a route registered with '/' URL.
from waitress import serve
import falcon
import json
class HelloResource:
def on_get(self, req, resp):
"""Handles GET requests"""
resp.text=json.dumps({"message":"Hello World"})
# This is the default status
resp.status = falcon.HTTP_200
# Default is JSON, so override
resp.content_type = falcon.MEDIA_JSON
def create():
app = falcon.App()
hello = HelloResource()
app.add_route('/', hello)
return app
app=create()
if __name__ == '__main__':
serve(app, host='0.0.0.0', port=8000)
Using unittest
testing.TestCase 扩展了 unittest ,以方便对使用 Falcon 编写的 WSGI/ASGI 应用程序进行功能测试。我们需要从这个基类继承并编写测试。
The testing.TestCase extends unittest to facilitate functional testing of WSGI/ASGI applications written with Falcon. We need to inherit from this base class and write the tests.
TestCase 子类中的测试函数的名称为 simulate_ (),其中 *' '* 表示 HTTP 方法,例如 GET、POST 等。这意味着我们必须获取 simulate_get() 函数的结果,并通过断言函数将其与预期结果进行比较。
The test functions in the TestCase subclass are of the name simulate_()* where ''* stands for HTTP methods like GET, POST etc. It means, we have to fetch the result of simulate_get() function and compare it with the expected result by assertion functions.
simulate_ ()* 函数接收两个参数。
The simulate_()* functions receive two arguments.
simulate_*(app, route)
以下是 test-myapp.py 的代码。它执行 simulate_get() 函数并将其结果与预期结果进行断言,并指示测试是否失败或通过。
Following is the code for test-myapp.py. It executes simulate_get() function and asserts its result with the anticipated result and indicates whether the test has failed or passed.
from falcon import testing
import myapp
class MyTestCase(testing.TestCase):
def setUp(self):
super(MyTestCase, self).setUp()
self.app = myapp.create()
class TestMyApp(MyTestCase):
def test_get_message(self):
doc = {'message': 'Hello world!'}
result = self.simulate_get('/')
self.assertEqual(result.json, doc)
if '__name__'=='__main__':
unittest.main()
使用以下命令运行上述测试 −
Run the above test with the help of the following command −
python -m unittest test-myapp.py
F
==============================================================
FAIL: test_get_message (test-myapp.TestMyApp)
--------------------------------------------------------------
Traceback (most recent call last):
File "E:\falconenv\test-myapp.py", line 17, in test_get_message
self.assertEqual(result.json, doc)
AssertionError: {'message': 'Hello World'} != {'message':
'Hello world!'}
- {'message': 'Hello World'}
? ^
+ {'message': 'Hello world!'}
? ^ +
--------------------------------------------------------------
Ran 1 test in 0.019s
FAILED (failures=1)
Using Pytest
要使用 PyTest 框架进行测试,你需要使用 PIP 实用程序安装它。
To perform testing using PyTest framework, you need to install it using PIP utility.
pip3 install pytest
要运行 test 函数,我们需要一个 testing.TestClient 类的对象。它模拟 WSGI 和 ASGI 应用程序的请求。这个对象首先通过将 Falcon 应用程序对象作为参数来获取。
To run a test function, we need an object of testing.TestClient class. It simulates the requests for WSGI and ASGI applications. This object is first obtained by giving Falcon application object as the argument.
我们运行 simulate_ ()* 函数并断言其结果是否与预期输出一致,以确定测试是否失败或通过。在这两个示例中,测试都失败了,因为 Hello World 消息中的“W”不同。应答者返回大写“W”,而测试函数中有小写“W”。
We run the simulate_()* functions and assert its result with the anticipated output to decide whether the test has failed or passed. In both the examples, the test fails because of difference in case of 'W' in Hello World message. The responder returns it with uppercase 'W' whereas the test function has it in lowercase.
from falcon import testing
import pytest
import myapp
@pytest.fixture()
def client():
return testing.TestClient(myapp.create())
def test_get_message(client):
doc = {'message': 'Hello world!'}
result = client.simulate_get('/')
assert result.json == doc
使用以下命令运行上述测试 −
Run the above test using the following command −
pytest test-myapp.py –v
=========== test session starts ==========================
platform win32 -- Python 3.8.6, pytest-7.1.2, pluggy-1.0.0 --
e:\falconenv\scripts\python.exe
cachedir: .pytest_cache
rootdir: E:\falconenv
plugins: anyio-3.5.0
collected 1 item
test-myapp.py::test_get_message FAILED
[100%]
==================== FAILURES =======================
_____________________________________________________
test_get_message
_____________________________________________________
client = <falcon.testing.client.TestClient object at 0x0000000003EAA6A0>
def test_get_message(client):
doc = {'message': 'Hello world!'}
result = client.simulate_get('/')
> assert result.json == doc
E AssertionError: assert {'message': 'Hello World'} ==
{'message': 'Hello world!'}
E Differing items:
E {'message': 'Hello World'} != {'message': 'Hello world!'}
E Full diff:
E - {'message': 'Hello world!'}
E ? ^ -
E + {'message': 'Hello World'}
E ? ^
test-myapp.py:42: AssertionError
============ short test summary info ==================
FAILED test-myapp.py::test_get_message - AssertionError:
assert {'message': 'Hello World'} == {'message': 'Hello
world!'}
============ 1 failed in 4.11s ========================
Python Falcon - Deployment
可以使用启用 mod_wsgi 模块的 Apache 服务器部署 Falcon Web 应用程序,就像任何 WSGI 应用程序一样。另一种方法是使用 uWSGI 或 gunicorn 进行部署。
It is possible to use Apache server enabled with the mod_wsgi module to deploy a Falcon web app, just as any WSGI app. Another alternative is to use uWSGI or gunicorn for deployment.
uWSGI 是一个快速且高度可配置的 WSGI 服务器。如果与 NGNIX 一起使用,它将以速度的形式在生产就绪环境中提供更好的性能。
The uWSGI is a fast and highly configurable WSGI server. If used along with NGNIX, it gives better performance in the form of speed in the production ready environment.
首先,在 Python 虚拟环境中使用 PIP 安装程序安装 Falcon 和 uWSGI,并使用 wsgi.py 将 Falcon 的应用程序对象公开给 uWSGI,如下所示 −
First, install Falcon and uWSGI in a Python virtual environment with PIP installer and expose the Falcon’s application object to uWSGI it with wsgi.py as below −
import os
import myapp
config = myproject.get_config(os.environ['MYAPP_CONFIG'])
application = myapp.create(config)
要配置 uWSGI,请准备一个 uwsgi.ini 脚本,如下所示 −
To configure uWSGI, prepare a uwsgi.ini script as below −
[uwsgi]
master = 1
vacuum = true
socket = 127.0.0.1:8080
enable-threads = true
thunder-lock = true
threads = 2
processes = 2
virtualenv = /path/to/venv
wsgi-file = venv/src/wsgi.py
chdir = venv/src
uid = myapp-runner
gid = myapp-runner
你现在可以像这样启动 uWSGI −
You can now start the uWSGI like this −
venv/bin/uwsgi -c uwsgi.ini
虽然 uWSGI 可以直接处理 HTTP 请求,但使用 NGINX 等反向代理可能会很有帮助。NGINX 本地支持 uWSGI 协议,以便有效地将请求代理到 uWSGI。
Although uWSGI may serve HTTP requests directly, it can be helpful to use a reverse proxy such as NGINX. NGINX natively supports the uwsgi protocol, for efficiently proxying requests to uWSGI.
安装 Ngnix,然后创建一个 NGINX conf 文件,如下所示 −
Install Ngnix and then create an NGINX conf file that looks something like this −
server {
listen 80;
server_name myproject.com;
access_log /var/log/nginx/myproject-access.log;
error_log /var/log/nginx/myproject-error.log warn;
location / {
uwsgi_pass 127.0.0.1:8080
include uwsgi_params;
}
}
终于启动了 Ngnix 服务器。您应该有正在运行的工作应用程序。
Finally start the Ngnix server. You should have a working application running.