如何自定义flask的响应类(customizing-the-flask-response-class)

2024-05-11 06:08

本文主要是介绍如何自定义flask的响应类(customizing-the-flask-response-class),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Response是Flask中响应客户端请求的类,然而在Flask应用中很少直接使用Response。Flask使用Response作为响应数据的容器,在响应客户端的请求时会添加一些创建HTTP响应所需要的附加信息。flask的响应数据是由应用的路由函数返回给客户端。然而,Flask也为应用提供了一种选择,来使开发者自己定义一些response类。本文将利用这一点来展示如何简化你应用的代码。

Flask的Response是如何工作的?

大多数的应用不会直接使用Flask的Response类,但是这不意味着框架中不使用Response。实际上,Flask为每个请求都创建响应对象。于是问题来了,它到底是如何工作的呢?
响应周期的起始时刻即:当Flask调用一个函数去处理请求的返回值的这个时间点。在web应用中,路由处理的最后都会调用render_template函数,render_template的主要功能是渲染引用的模板文件并作为字符串返回给客户端:

@app.route('/index')
def index():# ...return render_template('index.html')

但是你可能知道,一个Flask路由处理函数有两个可选的附加参数返回,一个是响应状态的编码,另一个是自定义的HTTP的报文类型:

@app.route('/data')
def index():# ...return render_template('data.json'), 201, {'Content-Type': 'application/json'}

Flask默认的Content-Type值是HTML,请求处理成功的默认编码值是200,在上边的例子中,Flaks将状态编码设置为201,响应内容的类型设置为JSON格式。
响应的内容由三个基本的单元组成:数据或者html的body,状态编码,Http报文类型。Flask应用实例中的make_response()函数实现了将路由函数中的返回值存储在Response对象中的功能。
你可以在Python的console中输入如下的代码来观察上述的处理过程:

>>> from flask import Flask
>>> app = Flask(__name__)
>>> app.make_response('Hello, World')
<Response 12 bytes [200 OK]>
>>> app.make_response(('Hello, World', 201))
<Response 12 bytes [201 CREATED]>

这里我创建了一个Flask应用实例,并调用make_response()方法创建了两个Response对象。第一个例子中,将一个字符串作为参数,response中的状态码和报文类型使用的是默认值。第二个例子中,参数是一个包含两个值的元组参数,并将状态码设置成为非默认值。
Flask将Response对象作为路由函数的响应的同时,有许多细节可以处理。例如,在after_request函数中可以用来插入或者修改http报文类型,改变html的内容或者状态码,甚至可以自定义一个完全不同的响应class来替代默认的Response。最后,Flask会将修改之后的响应对象返回给客户端。

Flask的Response类

下面我们来看看响应类中最核心的部分。下面这个类给出了我所认为的最核心的属性和方法:

class Response:charset = 'utf-8'default_status = 200default_mimetype = 'text/html'def __init__(self, response=None, status=None, headers=None,mimetype=None, content_type=None, direct_passthrough=False):pass@classmethoddef force_type(cls, response, environ=None):pass

这里需要注意的是,当你去看Flask源码时,看到的和上面的代码不一致。Flask中的Response 实际上非常简洁,这是由于Response 的核心功能是由Werkzeug框架中的Response 实现的。Werkzeug中的Response类继承自BaseResponse 类,
上边的属性和方法是由BaseResponse 定义的。

这三个类属性:charset, default_status 和default_mimetype定义了一些默认值。如果你的应用配置和默认值不符,可以通过继承Response 类来自定义属性,这样可以避免每次在响应时修改这些值。例如,如果你的应用是API,所有的路由返回的都是XML,你可以在自己定制的响应类中修改default_mimetype 为application/xml,这样Flask将默认的返回XML格式的响应。

我不会再详细的介绍init构造方法,但是需要注意的是Response 的构造方法接收三个重要的参数,响应主体,状态码和报头。在子类中,构造方法可以改变这个规则来创建特定的响应。

force_type()方法在响应类中扮演了十分重要的作用。在某些情况下,Werkzeug或Flask需要创建自己的响应对象,例如应用程序发生错误时,需要将错误响应返回给客户端。在这种情况下,响应对象是由框架创建的,而不是由应用产生的。当你在一个应用中创建特定的响应类型时,Flask和Werkzeug并不知道这个特定的响应类型的详细信息,因而框架还是默认的创建标准的响应类型。响应类中的force_type()方法负责将不同的响应实例转换成自己需要的形式。

我相信你一定会对force_type()的作用感到迷惑。实际上,每当Flask遇到响应对象与期望的类不符时,使用这个方法可以转换响应对象。在下边的第三个例子中,我将展示如何利用这个方法使得Flask的路由函数为每一个请求都返回一个支持诸如字典,列表,或者其他任何形式的特定对象的响应。
上边已经讲述了足够多的原理,在下边的章节中我会将这些编程技巧用代码实现。

使用定制的Response类
 为一个Flask应用配置一个定制的响应类是非常简单的。让我们看看下边这个例子:
from flask import Flask, Response
class MyResponse(Response):pass
app = Flask(__name__)
app.response_class = MyResponse
# …

这里我自己定义了一个名字是MyResponse 的响应类。通常我们定义自己的响应类时,只需要自定义一个Flask的Response 类的子类,并在此基础上添加或者修改某些行为。之后将app.response_class属性指定为自定义的类,就可以使Flask使用我们自己的响应类型。

Flask 类的属性response_class是类属性,因此作为从上边例子的变体,你可以创建一个Flask的子类来使用你自己的响应类:

from flask import Flask, Response
class MyResponse(Response):pass
class MyFlask(Flask)response_class = MyResponse
app = MyFlask(__name__)
例子#1:改变Response 的默认值

第一个例子十分简单。比如你的应用在所有的endpoints都返回XML.对于这种情形,我们只需要将默认的content type设置为application/xml即可。这个只需要两行代码就可以实现。

class MyResponse(Response):default_mimetype = 'application/xml'

很简单,对不对?如果将这个类设置为应用的默认响应,你可以在路由函数中返回XML而不必设置
content type。例如:

@app.route('/data')
def get_data():return '''<?xml version="1.0" encoding="UTF-8"?>
<person><name>John Smith</name>
</person>
'''

如果使用默认的响应类,路由将会默认接收 application/xml格式的内容类型。如果你需要不同的
content type,你只需要在正常的路由函数返回值里覆盖一下默认值即可,

@app.route('/')
def index():return '<h1>Hello, World!</h1>', {'Content-Type': 'text/html'}
例子#2:自动地决定Content Type

下边的这个例子有一些复杂。假定这个应用中的HTML 和XML路由数量相当,这时使用第一种方法就十分低效,因为你无论怎么设置默认的格式,都有一半数量的路由需要覆盖默认的content type。
一个比较好的方案是:创建一个响应类型可以依据响应的内容自行决定使用的content type。下边给出一个实例:

class MyResponse(Response):def __init__(self, response, **kwargs):if 'mimetype' not in kwargs and 'contenttype' not in kwargs:if response.startswith('<?xml'):kwargs['mimetype'] = 'application/xml'return super(MyResponse, self).__init__(response, **kwargs)

这个例子中,一开始response中没有指定content type。接下来,如果response文本是以<?xml
开头,这说明数据是以XML文档格式编码。如果上边的两个条件均为真,将XML content type以
字典的形式作为参数发送给父类的构造方法.
在这个response类中,任何XML格式的文档都会自动的接收XML content type,而其他的响应将继续使用默认的content type。而且在所有的类中,我们仍然可以自动的指定我们需要的content type类型。

例子#3:自动地设定JSON响应

最后的例子将会处理Flask的中非常麻烦的情形。使用Flask的API返回JSON格式是一种非常普遍的情形,这需要你调用jsonify()函数将Python 字典转换成JSON 格式,并在响应中设置content type为JSON.下边是一个路由处理的例子:

@app.route('/data')
def get_data():return jsonify({'foo': 'bar'})

遗憾的是,所有需要返回JSON的路由函数都需要这么做,这会导致大量API的结尾都会重复的调用jsonify()函数。从代码可读性的角度考虑,是否有方法可以替代?

@app.route('/data')
def get_data():return {'foo': 'bar'}

这里定义了一个响应类,可以支持上边的语法,使得所有的路由函数不需要再返回JSON:

class MyResponse(Response):@classmethoddef force_type(cls, rv, environ=None):if isinstance(rv, dict):rv = jsonify(rv)return super(MyResponse, cls).force_type(rv, environ)

Flask 中路由handler 函数只能处理有限的几种类型。这些类型包括str, unicode, bytes, bytearray
但是当你返回一些不支持的类型,例如上面例子中的字典,Flask会如何处理呢?如果返回的响应类型与期望的类型不符,Flask将其认定为未知的响应类型,此时不会创建response对象返回信息,而是调用类方法force_type()强制转换这个未知类型。在这个例子中,子类自定义的响应类覆盖重写这个方法,自动转换返回值是字典的情形。转换是通过在调用父类方法之前,先调用jsonify()方法来实现。
上面的这种技巧不会影响其他正常的响应函数的功能。这是由于对于任何返回正常响应类来说,子类没有做任何事情,所有的请求透明的传递给父类。

原文链接

https://blog.miguelgrinberg.com/post/customizing-the-flask-response-class

这篇关于如何自定义flask的响应类(customizing-the-flask-response-class)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/978709

相关文章

SpringBoot定制JSON响应数据的实现

《SpringBoot定制JSON响应数据的实现》本文主要介绍了SpringBoot定制JSON响应数据的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们... 目录前言一、如何使用@jsonView这个注解?二、应用场景三、实战案例注解方式编程方式总结 前言

CSS自定义浏览器滚动条样式完整代码

《CSS自定义浏览器滚动条样式完整代码》:本文主要介绍了如何使用CSS自定义浏览器滚动条的样式,包括隐藏滚动条的角落、设置滚动条的基本样式、轨道样式和滑块样式,并提供了完整的CSS代码示例,通过这些技巧,你可以为你的网站添加个性化的滚动条样式,从而提升用户体验,详细内容请阅读本文,希望能对你有所帮助...

Spring MVC如何设置响应

《SpringMVC如何设置响应》本文介绍了如何在Spring框架中设置响应,并通过不同的注解返回静态页面、HTML片段和JSON数据,此外,还讲解了如何设置响应的状态码和Header... 目录1. 返回静态页面1.1 Spring 默认扫描路径1.2 @RestController2. 返回 html2

VUE动态绑定class类的三种常用方式及适用场景详解

《VUE动态绑定class类的三种常用方式及适用场景详解》文章介绍了在实际开发中动态绑定class的三种常见情况及其解决方案,包括根据不同的返回值渲染不同的class样式、给模块添加基础样式以及根据设... 目录前言1.动态选择class样式(对象添加:情景一)2.动态添加一个class样式(字符串添加:情

使用Python实现批量访问URL并解析XML响应功能

《使用Python实现批量访问URL并解析XML响应功能》在现代Web开发和数据抓取中,批量访问URL并解析响应内容是一个常见的需求,本文将详细介绍如何使用Python实现批量访问URL并解析XML响... 目录引言1. 背景与需求2. 工具方法实现2.1 单URL访问与解析代码实现代码说明2.2 示例调用

SpringBoot 自定义消息转换器使用详解

《SpringBoot自定义消息转换器使用详解》本文详细介绍了SpringBoot消息转换器的知识,并通过案例操作演示了如何进行自定义消息转换器的定制开发和使用,感兴趣的朋友一起看看吧... 目录一、前言二、SpringBoot 内容协商介绍2.1 什么是内容协商2.2 内容协商机制深入理解2.2.1 内容

提示:Decompiled.class file,bytecode version如何解决

《提示:Decompiled.classfile,bytecodeversion如何解决》在处理Decompiled.classfile和bytecodeversion问题时,通过修改Maven配... 目录问题原因总结问题1、提示:Decompiled .class file,China编程 bytecode

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

自定义类型:结构体(续)

目录 一. 结构体的内存对齐 1.1 为什么存在内存对齐? 1.2 修改默认对齐数 二. 结构体传参 三. 结构体实现位段 一. 结构体的内存对齐 在前面的文章里我们已经讲过一部分的内存对齐的知识,并举出了两个例子,我们再举出两个例子继续说明: struct S3{double a;int b;char c;};int mian(){printf("%zd\n",s

深入理解RxJava:响应式编程的现代方式

在当今的软件开发世界中,异步编程和事件驱动的架构变得越来越重要。RxJava,作为响应式编程(Reactive Programming)的一个流行库,为Java和Android开发者提供了一种强大的方式来处理异步任务和事件流。本文将深入探讨RxJava的核心概念、优势以及如何在实际项目中应用它。 文章目录 💯 什么是RxJava?💯 响应式编程的优势💯 RxJava的核心概念