媒体¶
Falcon允许轻松和定制的互联网媒体类型处理。默认情况下,Falcon只为JSON和HTML(URL编码和多部分)表单启用处理程序。但是,可以通过 falcon.RequestOptions
和 falcon.ResponseOptions
在您的 falcon.App
.
备注
WebSocket媒体的处理方式与常规HTTP请求不同。有关WebSocket媒体处理程序的信息,请参阅: 媒体处理程序 在WebSocket部分。
使用¶
如果要创建JSON API,则需要零配置。简单使用 get_media()
和 media
(WSGI),或 get_media()
和 media
(ASGI)让Falcon帮你做重活。
import falcon
class EchoResource:
def on_post(self, req, resp):
# Deserialize the request body based on the Content-Type
# header in the request, or the default media type
# when the Content-Type header is generic ('*/*') or
# missing.
obj = req.get_media()
message = obj.get('message')
# The framework will look for a media handler that matches
# the response's Content-Type header, or fall back to the
# default media type (typically JSON) when the app does
# not explicitly set the Content-Type header.
resp.media = {'message': message}
resp.status = falcon.HTTP_200
import falcon
class EchoResource:
async def on_post(self, req, resp):
# Deserialize the request body. Note that the ASGI version
# of this method must be awaited.
obj = await req.get_media()
message = obj.get('message')
# The framework will look for a media handler that matches
# the response's Content-Type header, or fall back to the
# default media type (typically JSON) when the app does
# not explicitly set the Content-Type header.
resp.media = {'message': message}
resp.status = falcon.HTTP_200
警告
一次 falcon.Request.get_media()
或 falcon.asgi.Request.get_media()
在请求上调用时,它将使用请求的正文流。为避免不必要的开销,Falcon将仅在第一次引用请求介质时对其进行处理。后续交互将使用缓存的对象。
正在验证媒体¶
Falcon目前只提供一个JSON模式媒体验证程序;但是,JSON模式非常通用,可以用来验证JSON也支持的任何反序列化媒体类型(如dicts、list等)。
- falcon.media.validators.jsonschema.validate(req_schema=None, resp_schema=None, is_async=False)[源代码]¶
验证
req.media
使用JSON架构。这个装饰器通过
jsonschema
PYPI提供的包。语义验证通过 格式 已为实现的默认检查程序启用关键字jsonschema.FormatChecker
.如果请求媒体验证失败,
MediaValidationError
是由装饰师养大的。默认情况下,此错误呈现为400 (HTTPBadRequest
)的回应title
和description
属性来解释验证失败,但可以通过添加自定义错误来修改此行为handler
为MediaValidationError
。- 关键字参数:
req_schema (dict) -- 遵循JSON模式规范的字典。将根据此架构验证请求。
resp_schema (dict) -- 遵循JSON模式规范的字典。将根据此架构验证响应。
is_async (bool) -- 设置为
True
让ASGI应用程序提供修饰的响应器是协程函数的提示(即,它是用async def
)或返回可等待的协程对象。通常,当使用async def
产生的函数对象被标记,以指示它在被调用时返回协程,并且这可以被自动检测到。但是,可以使用常规函数返回一个可等待的协程对象,在这种情况下,需要一个提示来让框架知道预期会发生什么。此外,在使用Cython化的协程函数时,始终需要提示,因为Cython不会以可以预先检测到的方式标记它们,即使函数是使用async def
。
示例
from falcon.media.validators import jsonschema # -- snip -- @jsonschema.validate(my_post_schema) def on_post(self, req, resp): # -- snip --
from falcon.media.validators import jsonschema # -- snip -- @jsonschema.validate(my_post_schema) async def on_post(self, req, resp): # -- snip --
from falcon.media.validators import jsonschema # -- snip -- @jsonschema.validate(my_post_schema, is_async=True) async def on_post(self, req, resp): # -- snip --
如果JSON模式不满足您的需求,那么定制验证器的实现方式可能与上面的方法类似。
内容类型协商¶
Falcon目前只支持开箱即用的部分协商。默认情况下,当 get_media()
方法或 media
属性时,框架尝试基于 Content-Type
标题值。Falcon没有提供的缺失链接是 Accept
由用户提供的头和 Content-Type
在响应上设置标头。
如果您确实需要完整的协商,那么使用中间件很容易弥合这一差距。下面是一个如何做到这一点的示例:
class NegotiationMiddleware:
def process_request(self, req, resp):
resp.content_type = req.accept
class NegotiationMiddleware:
async def process_request(self, req, resp):
resp.content_type = req.accept
异常处理¶
Falcon版本3更新了处理程序引发的异常的处理方式:
Falcon允许媒体处理程序尝试反序列化空体。对于不允许将空正文作为有效值的媒体类型,例如
JSON
,一个实例falcon.MediaNotFoundError
应该提高。默认情况下,此错误将呈现为400 Bad Request
对客户端的响应。通过将一个值传递给default_when_empty
参数时调用Request.get_media()
。在本例中,该值将由调用返回。如果处理程序在分析非空正文时遇到错误,
falcon.MediaMalformedError
应该提高。原始异常(如果有)存储在__cause__
引发的实例的属性。默认情况下,此错误将呈现为400 Bad Request
对客户端的响应。
如果处理程序在分析正文时引发任何异常,则 Request.get_media()
或 Request.media
将导致同一异常的重新引发,除非该异常是 falcon.MediaNotFoundError
并将默认值传递给 default_when_empty
当前调用的属性。
外部处理程序应更新其逻辑以与内部Falcon处理程序对齐。
替换默认处理程序¶
默认情况下,框架安装 falcon.media.JSONHandler
, falcon.media.URLEncodedFormHandler
,以及 falcon.media.MultipartFormHandler
对于 application/json
, application/x-www-form-urlencoded
,以及 multipart/form-data
分别为媒体类型。
在创建App对象时,您可以添加或完全替换所有处理程序。例如,假设您想要编写一个发送和接收 MessagePack 。我们可以很容易地做到这一点,方法是告诉Falcon API我们需要默认的媒体类型 application/msgpack
,然后创建一个新的 Handlers
对象将该媒体类型映射到适当的处理程序。
下面的示例演示如何替换默认处理程序。因为Falcon提供了一个 MessagePackHandler
这在默认情况下是不启用的,我们在下面的示例中使用它。不过,您始终可以通过替身 custom media handler 根据需要。
import falcon
from falcon import media
handlers = media.Handlers({
falcon.MEDIA_MSGPACK: media.MessagePackHandler(),
})
app = falcon.App(media_type=falcon.MEDIA_MSGPACK)
app.req_options.media_handlers = handlers
app.resp_options.media_handlers = handlers
或者,您也可以简单地更新现有的 Handlers
对象以保留默认处理程序:
import falcon
from falcon import media
extra_handlers = {
falcon.MEDIA_MSGPACK: media.MessagePackHandler(),
}
app = falcon.App()
app.req_options.media_handlers.update(extra_handlers)
app.resp_options.media_handlers.update(extra_handlers)
这个 falcon
模块为常见媒体类型提供了许多常量。另请参阅: 媒体类型常量 。
备注
已配置的 falcon.Response
JSON处理程序还用于序列化 falcon.HTTPError
以及 json
的属性 falcon.asgi.SSEvent
。中配置的JSON处理程序 falcon.Request
由以下用户使用 falcon.Request.get_param_as_json()
若要反序列化查询参数,请执行以下操作。
因此,在实现JSON媒体类型的自定义处理程序时,需要同步接口方法,这意味着 falcon.media.BaseHandler.serialize()
和 falcon.media.BaseHandler.deserialize()
,即使在 ASGI
申请。默认的JSON处理程序, falcon.media.JSONHandler
已经实现了使用这两种类型的应用程序所需的方法。
支持的处理程序类型¶
- class falcon.media.JSONHandler(dumps=None, loads=None)[源代码]¶
JSON媒体处理程序。
此处理程序使用Python的标准
json
库在默认情况下,但可以根据需要轻松配置为使用许多第三方JSON库中的任何一个。例如,通过使用替代库,您通常可以在cpython下实现显著的性能提升。在这方面的好选择包括 orjson , python-rapidjson 和 mujson .此处理程序将引发
falcon.MediaNotFoundError
当尝试分析空体时,或者falcon.MediaMalformedError
如果在解析正文时发生错误。备注
如果您要部署到Pypy,我们建议您坚持使用标准库的JSON实现,因为与第三方库相比,它在大多数情况下都会更快。
定制JSON库
您可以使用自定义JSON库替换默认的JSON处理程序(另请参阅: 替换默认处理程序 )。覆盖默认的JSON实现只需指定所需的
dumps
和loads
功能::import falcon from falcon import media import rapidjson json_handler = media.JSONHandler( dumps=rapidjson.dumps, loads=rapidjson.loads, ) extra_handlers = { 'application/json': json_handler, } app = falcon.App() app.req_options.media_handlers.update(extra_handlers) app.resp_options.media_handlers.update(extra_handlers)
自定义序列化参数
即使您决定坚持使用stdlib
json.dumps
和json.loads
,您可以使用以下命令包装它们functools.partial
方法支持的自定义序列化或反序列化参数dumps
和loads
函数(另请参阅: 美化JSON响应 ):import falcon from falcon import media from functools import partial json_handler = media.JSONHandler( dumps=partial( json.dumps, default=str, sort_keys=True, ), ) extra_handlers = { 'application/json': json_handler, } app = falcon.App() app.req_options.media_handlers.update(extra_handlers) app.resp_options.media_handlers.update(extra_handlers)
默认情况下,
ensure_ascii
传递给json.dumps
功能。如果您重写dumps
函数,则需要显式设置ensure_ascii
至False
以便能够将Unicode字符序列化为UTF-8。这可以通过使用functools.partial
要应用所需的关键字参数,请执行以下操作。也如上一段所示,您可以使用同样的技术来自定义dumps
和loads
功能::from functools import partial from falcon import media import rapidjson json_handler = media.JSONHandler( dumps=partial( rapidjson.dumps, ensure_ascii=False, sort_keys=True ), )
定制JSON编码器
您也可以覆盖缺省值
JSONEncoder
通过使用自定义编码器并更新媒体处理程序application/json
键入以使用该名称::import json from datetime import datetime from functools import partial import falcon from falcon import media class DatetimeEncoder(json.JSONEncoder): """Json Encoder that supports datetime objects.""" def default(self, obj): if isinstance(obj, datetime): return obj.isoformat() return super().default(obj) app = falcon.App() json_handler = media.JSONHandler( dumps=partial(json.dumps, cls=DatetimeEncoder), ) extra_handlers = { 'application/json': json_handler, } app.req_options.media_handlers.update(extra_handlers) app.resp_options.media_handlers.update(extra_handlers)
备注
在测试使用定制JSON编码器的应用程序时,请记住
TestClient
是与应用程序分离的,它模拟请求,就好像它们是由第三方客户端(只是SANS网络)执行的一样。因此,传递 json 参数设置为 simulate_* 方法将有效地使用stdlib的json.dumps()
。如果要序列化用于测试的自定义对象,则需要自己将它们转储到字符串中,并使用 body 参数来代替(随附application/json
内容类型报头)。- 关键字参数:
dumps (func) -- 在序列化JSON响应时使用的函数。
loads (func) -- 反序列化JSON请求时使用的函数。
- class falcon.media.MessagePackHandler[源代码]¶
使用生成的处理程序
msgpack
模块。此处理程序使用
msgpack.unpackb()
和msgpack.Packer().pack()
。MessagePackbin
类型用于区分Unicode字符串(类型为str
)和字节字符串(类型为bytes
)。此处理程序将引发
falcon.MediaNotFoundError
当尝试分析空体时,它将引发falcon.MediaMalformedError
如果在解析正文时发生错误。备注
此处理程序需要额外的
msgpack
软件包(0.5.2或更高版本),必须安装在falcon
来自Pypi:$ pip install msgpack
- class falcon.media.MultipartFormHandler(parse_options=None)[源代码]¶
多部分表单(内容类型
multipart/form-data
)媒体处理程序。这个
multipart/form-data
HTML5表单的媒体类型在中定义 RFC 7578 。多部分媒体类型本身在中定义 RFC 2046 section 5.1 。
备注
与其他框架中的许多表单解析实现不同,该处理程序不会立即使用流。相反,在迭代媒体对象时,按需使用流并将其解析为单独的正文部分。
有关解析申请表的示例,另请参阅: 多部分形式 。
- class falcon.media.URLEncodedFormHandler(keep_blank=True, csv=False)[源代码]¶
URL编码的表单数据处理程序。
此处理程序分析
application/x-www-form-urlencoded
将HTML表单添加到dict
,类似于URL查询参数的解析方式。空的正文将被解析为空的字典。反序列化时,此处理程序将引发
falcon.MediaMalformedError
如果请求有效负载不能被解析为ASCII,或者如果有效负载中的任何URL编码字符串不是有效的UTF-8。如文档所示,
urllib.parse.urlencode
,序列化时,媒体对象必须是dict
或由两个元素组成的序列tuple
如果媒体对象中的任何值都是序列,则将每个序列元素转换为单独的参数。
自定义处理程序类型¶
如果Falcon没有支持您的用例的Internet媒体类型处理程序,您可以使用Falcon提供的抽象基类轻松实现您自己的,如下所述。
总体而言 WSGI
应用程序仅使用同步方法,而 ASGI
应用程序只使用异步应用程序。被处理的JSON是一个例外,因为它也被框架的其他部分使用,而不仅仅是在媒体处理中。请参阅 note above 了解更多详细信息。
- class falcon.media.BaseHandler[源代码]¶
Internet媒体类型处理程序的抽象基类。
- serialize(media: object, content_type: str) bytes [源代码]¶
上序列化媒体对象
falcon.Response
。默认情况下,此方法引发
NotImplementedError
。因此,必须覆盖它才能使用WSGI应用程序。如果子类仅与ASGI应用程序一起使用,则它们可以忽略此方法,只要它们重写serialize_async()
。备注
JSON媒体处理程序是一个例外,它要求也为ASGI应用程序实现同步版本。请参阅 this section 了解更多详细信息。
- async serialize_async(media: object, content_type: str) bytes [源代码]¶
上序列化媒体对象
falcon.Response
。此方法类似于
serialize()
只是它是异步的。默认实现只是调用serialize()
。如果媒体对象可能是可等待的,或者应该异步读取,则子类必须覆盖默认实现才能处理这种情况。备注
默认情况下,
serialize()
方法引发NotImplementedError
。因此,子类必须重写serialize()
或serialize_async()
以便与ASGI应用程序兼容。
- deserialize(stream: IO, content_type: str, content_length: Optional[int]) object [源代码]¶
反序列化
falcon.Request
身体。默认情况下,此方法引发
NotImplementedError
。因此,必须覆盖它才能使用WSGI应用程序。如果子类仅与ASGI应用程序一起使用,则它们可以忽略此方法,只要它们重写deserialize_async()
。备注
JSON媒体处理程序是一个例外,它要求也为ASGI应用程序实现同步版本。请参阅 this section 了解更多详细信息。
- async deserialize_async(stream: IO, content_type: str, content_length: Optional[int]) object [源代码]¶
反序列化
falcon.Request
身体。此方法类似于
deserialize()
只是它是异步的。缺省实现适应同步deserialize()
方法通过io.BytesIO
。为提高性能,媒体处理程序应重写此方法。备注
默认情况下,
deserialize()
方法引发NotImplementedError
。因此,子类必须重写deserialize()
或deserialize_async()
以便与ASGI应用程序兼容。
- exhaust_stream = False¶
是否在完成反序列化后耗尽输入流。
对于不一定使用整个流,但反序列化的媒体对象是完整的并且不涉及进一步的流的处理程序来说,用尽流可能是有用的。
小技巧
为了在 Falcon app ,则必须将类的实例添加到应用程序的媒体处理程序(在中指定) RequestOptions
和 ResponseOptions
,分别)。
参见: 替换默认处理程序 .
处理程序映射¶
媒体类型常量¶
这个 falcon
模块为常见的媒体类型字符串提供了许多常量,包括:
falcon.MEDIA_JSON
falcon.MEDIA_MSGPACK
falcon.MEDIA_MULTIPART
falcon.MEDIA_URLENCODED
falcon.MEDIA_YAML
falcon.MEDIA_XML
falcon.MEDIA_HTML
falcon.MEDIA_JS
falcon.MEDIA_TEXT
falcon.MEDIA_JPEG
falcon.MEDIA_PNG
falcon.MEDIA_GIF