如何自定义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

相关文章

【前端学习】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的核心概念

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。

Oracle type (自定义类型的使用)

oracle - type   type定义: oracle中自定义数据类型 oracle中有基本的数据类型,如number,varchar2,date,numeric,float....但有时候我们需要特殊的格式, 如将name定义为(firstname,lastname)的形式,我们想把这个作为一个表的一列看待,这时候就要我们自己定义一个数据类型 格式 :create or repla

简单的角色响应鼠标而移动

actor类 //处理移动距离,核心是找到角色坐标在世界坐标的向量的投影(x,y,z),然后在世界坐标中合成,此CC是在地面行走,所以Y轴投影始终置为0; using UnityEngine; using System.Collections; public class actor : MonoBehaviour { public float speed=0.1f; CharacterCo

HTML5自定义属性对象Dataset

原文转自HTML5自定义属性对象Dataset简介 一、html5 自定义属性介绍 之前翻译的“你必须知道的28个HTML5特征、窍门和技术”一文中对于HTML5中自定义合法属性data-已经做过些介绍,就是在HTML5中我们可以使用data-前缀设置我们需要的自定义属性,来进行一些数据的存放,例如我们要在一个文字按钮上存放相对应的id: <a href="javascript:" d

一步一步将PlantUML类图导出为自定义格式的XMI文件

一步一步将PlantUML类图导出为自定义格式的XMI文件 说明: 首次发表日期:2024-09-08PlantUML官网: https://plantuml.com/zh/PlantUML命令行文档: https://plantuml.com/zh/command-line#6a26f548831e6a8cPlantUML XMI文档: https://plantuml.com/zh/xmi

argodb自定义函数读取hdfs文件的注意点,避免FileSystem已关闭异常

一、问题描述 一位同学反馈,他写的argo存过中调用了一个自定义函数,函数会加载hdfs上的一个文件,但有些节点会报FileSystem closed异常,同时有时任务会成功,有时会失败。 二、问题分析 argodb的计算引擎是基于spark的定制化引擎,对于自定义函数的调用跟hive on spark的是一致的。udf要通过反射生成实例,然后迭代调用evaluate。通过代码分析,udf在

类型信息:反射-Class

在说反射前提一个概念:RTTI(在运行时,识别一个对象的类型) public class Shapes {public static void main(String[] args) {List<Shape> shapes = Arrays.asList(new Circle(), new Square(), new Triangle());for (Shape shape : shapes