flask使用心得

Flask开发

flask不像django那样重量,它非常轻巧,可由程序员自己深度掌控。很适合用来做一些原型快速开发。
一个hello world的例子:

from flask import Flask
import loggingapp = Flask(__name__)@app.route('/')
def hello_world():app.logger.info('hello called')return 'hello, lee'if __name__ == '__main__':handler = logging.FileHandler('flask.log')handler.setFormatter(logging.Formatter('[%(process)d|%(thread)d][%(asctime)s] [%(levelname)s] %(message)s'))app.logger.setLevel(logging.INFO)app.logger.addHandler(handler)app.run(host='0.0.0.0')   

首先,flask使用注解来绑定url和其处理函数,比django更直观,近似于java web框架的做法了。
其次,flask对日志的使用,就跟普通程序里使用logging一样,不用像django那样受限于框架。

获得incoming request和session

直接访问全局变量request和session即可。

构建response

rv = {'status': script.status, 'msg': msg}
Response(json.dumps(rv), mimetype='application/json')

request

flask里的request看起来是一个全局变量,但其实是threadLocal的,可以放心使用,session变量也是类似的情况。参看该文。

另外,flask的request使用了werkzeug库来包装,它提供了一些成员:

request.form 存放的是request消息体里的数据,相当于spring的@RequestBody注解;

request.args 存放的是url路径中的参数,类似于spring的@RequestParam注解。

具体分析参看该文。

下载文件

有两种方法:

  1. 将文件放到通过url可访问到的路径
  2. 使用flask.send_from_directory,可从url不能访问到的路径传输文件

注意:send_from_directory会做路径检查,确保没有…这样的可能引发安全问题的路径。

flask底层的文件传输有几种策略:

  1. WSGI server’s file_wrapper support
  2. X-Sendfile头

静态资源服务

flask的send_static_file实际调用的就是send_from_directory(顺带说一下,网上说send_static_file不安全,其实既然send_from_directory是安全的,那send_static_file就也是安全的!)。因此,flask对静态资源的支持跟文件下载是同一原理。

这里有个问题,是让nginx这样的代理服务器代为管理静态资源(nginx在这方面是非常高效的),还是由flask来处理静态资源?

SO上有一段说明:

The preferred method is to use nginx or another web server to serve static files; they'll be able to do it more efficiently than Flask.

我理解,这里面有2点值得注意:

  1. 静态资源的缓存问题,为了效率起见,我们不可能每次都去重新传输一个文件;
  2. 如果有多个flask实例,这些实例间可以共享同一份静态资源,此时可以在多个flask实例前再套一个nginx,由nginx在负载均衡的同时,提供静态资源服务。

flask caching

参考此文。

Blueprint自动添加url前缀

使用Blueprint,可以很方便的为rest请求和静态资源增加url前缀,类似于spring的server.servlet.context-path

先定义蓝图(view.py文件):

main_view = Blueprint('main-view', __name__, static_folder='webapp/')

然后在该蓝图下写路由:

@main_view.route('/')
def home_page():gen_session_if_needed()return render_template('index.html',example_content='',example_filename='',prerequisite_content='',prerequisite_filename='')

最后注册到flask里面:

from view import main_viewapp.register_blueprint(main_view)

注意:蓝图默认不会注册静态资源的路由,需要显示用static_folder来指定。

Blueprint的原理

def route(self, rule, **options):"""Like :meth:`Flask.route` but for a blueprint.  The endpoint for the:func:`url_for` function is prefixed with the name of the blueprint."""## f是url的映射函数def decorator(f):endpoint = options.pop("endpoint", f.__name__)## 缓存映射函数self.add_url_rule(rule, endpoint, f, **options)return freturn decoratordef add_url_rule(self, rule, endpoint=None, view_func=None, **options):## 这里记录的是BlueprintSetupState.add_url_rule函数self.record(lambda s: s.add_url_rule(rule, endpoint, view_func, **options))    def record(self, func):"""Registers a function that is called when the blueprint isregistered on the application.  This function is called with thestate as argument as returned by the :meth:`make_setup_state`method."""if self._got_registered_once and self.warn_on_modifications:from warnings import warnwarn(Warning("The blueprint was already registered once ""but is getting modified now.  These changes ""will not show up."))self.deferred_functions.append(func)        def register(self, app, options, first_registration=False):"""Called by :meth:`Flask.register_blueprint` to register all viewsand callbacks registered on the blueprint with the application. Createsa :class:`.BlueprintSetupState` and calls each :meth:`record` callbackwith it.:param app: The application this blueprint is being registered with.:param options: Keyword arguments forwarded from:meth:`~Flask.register_blueprint`.:param first_registration: Whether this is the first time thisblueprint has been registered on the application."""self._got_registered_once = True## 创建一个BlueprintSetupStatestate = self.make_setup_state(app, options, first_registration)## 处理静态资源 if self.has_static_folder:state.add_url_rule(self.static_url_path + "/<path:filename>",view_func=self.send_static_file,endpoint="static",)## 调用前面缓存的url映射函数for deferred in self.deferred_functions:deferred(state)        
...
...## BlueprintSetupState.add_url_rule函数,真正添加flask的url路由的地方
def add_url_rule(self, rule, endpoint=None, view_func=None, **options):"""A helper method to register a rule (and optionally a view function)to the application.  The endpoint is automatically prefixed with theblueprint's name."""##自动为rule添加url_prefixif self.url_prefix is not None:if rule:rule = "/".join((self.url_prefix.rstrip("/"), rule.lstrip("/")))else:rule = self.url_prefixoptions.setdefault("subdomain", self.subdomain)if endpoint is None:endpoint = _endpoint_from_view_func(view_func)defaults = self.url_defaultsif "defaults" in options:defaults = dict(defaults, **options.pop("defaults"))# 然后加到flask app的url路由中,由于该函数肯定是在register blueprint之后调,self.app必然已设置    self.app.add_url_rule(rule,"%s.%s" % (self.blueprint.name, endpoint),view_func,defaults=defaults,**options)

总结:蓝图会事先缓存url映射函数,当注册到flask时(通过app.register_blueprint)才真正去添加url路由。

常见问题

结尾有无反斜杠的区别

我们的根url结尾最好加一个斜杠,否则会找不到链接,故障现象是zuul里压根就没有请求的url。因为我们的代码一般是这么写的:

@main_view.route('/')
def home_page():gen_session_if_needed()return render_template('index.html',example_content='',example_filename='',prerequisite_content='',prerequisite_filename='',url_prefix=SCIMATE_URL_PREFIX)

这就表示根url最后必须要有一个斜杠。

Flask部署

前端都使用nginx做反向代理及负载均衡。

结合gevent

Flask+gevent+gevent.pywsgi:使用gevent自带的WSGIServer

Flask+gevent+uwsgi: uwsgi里有使用gevent的选项

Flask+gevent+gunicorn:gunicorn里有使用gevent的选项

不使用gevent

Flask+uwsgi

Flask+gunicorn

参考文档:

flask启动

启动命令:

flask run -h 0.0.0.0 -p 8080

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/46141.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Azure应用程序网关

文章目录 什么是应用程序网关实战演练创建虚拟网络创建虚拟机创建应用程序网关测试搭建结果 什么是应用程序网关 Azure应用程序网关是一种托管服务&#xff0c;用于提供安全、可缩放的 Web 应用程序前端点的应用程序传送控制和保护。它可以通过 SSL 终止、cookie 基于会话持久…

神经网络基础-神经网络补充概念-58-端到端的深度学习

概念 端到端深度学习&#xff08;End-to-End Deep Learning&#xff09;是指将整个问题的解决过程从输入到输出都交由深度神经网络来完成&#xff0c;无需手工设计复杂的特征提取、预处理或后处理步骤。这种方法的核心思想是通过神经网络自动地学习适合任务的特征表示和映射&a…

Centos 7 通过Docker 安装MySQL 8.0.33实现数据持久化及my.cnf配置

一、docker 启动MySQL容器实现数据持久化 要在 CentOS 7 上使用 Docker 启动 MySQL 8.0.33&#xff0c;并配置 MySQL 的 my.cnf 文件&#xff0c;同时实现 MySQL 数据的持久化&#xff0c;可以按照以下步骤进行操作&#xff1a; 1、安装 Docker&#xff1a;确保你在 CentOS 7 …

【计算机网络八股】计算机网络(一)

目录 计算机网络的各层协议及作用&#xff1f;TCP和UDP的区别&#xff1f;UDP 和 TCP 对应的应用场景是什么&#xff1f;详细介绍一下 TCP 的三次握手机制&#xff1f;为什么需要三次握手&#xff0c;而不是两次&#xff1f;为什么要三次握手&#xff0c;而不是四次&#xff1f…

[C语言]分支语句和循环语句

[C语言]分支语句和循环语句 文章目录 [C语言]分支语句和循环语句C语言语句分类分支语句if语法结构else的匹配规则switch语句switch语句中的breakswitch语句中default 循环语句while循环while循环中的break和continuefor循环for循环中的break和continuefor循环的变种do while循环…

广告牌安全传感器,实时监测事故隐患尽在掌握

在现代城市中&#xff0c;广告牌作为商业宣传的重要媒介&#xff0c;已然成为城市中一道独特的风景线。然而&#xff0c;随着城市迅速发展&#xff0c;广告牌的安全问题也引起了大众关注。广告招牌一般悬挂于建筑物高处&#xff0c;量大面大。由于设计、材料、施工方法的缺陷&a…

函数栈帧的创建与销毁

目录 引言 基础知识 内存模型 ​ 寄存器的种类与功能 常用的汇编指令 函数栈帧创建与销毁 main()函数栈帧的创建 NO1. NO2. NO3. NO4. NO5. NO6. main()函数栈帧变量的创建 调用Add()函数栈帧的预备工作——传参 NO1. NO2. NO3. Add()函数栈帧的创建 …

对接海康明眸门禁设备-删除人员信息

对接海康明眸门禁设备-删除人员信息 文中登录 退出登录 长连接和海康hCNetSDK等接口 见文章 初始SDK和登录 /*** 删除人脸 IotCommDataResult 自定义类 收集结果*/Overridepublic List<IotCommDataResult> deleteFace(IotCameraParam camera, Collection<Long> us…

C语言入门_Day 6布尔数与比较运算

目录 前言 1.布尔数 2.比较运算 3.易错点 4.思维导图 前言 除了算术计算以外&#xff0c;编程语言中还会大量使用比较运算&#xff0c;并会根据比较运算的结果是“真”还是“假”&#xff0c;来执行不同的代码。 当你想买一杯奶茶&#xff0c;准备支付的时候&#xff0c;支…

一文解析HTTP与HTTPS,它们的区别和联系

一文解析HTTP与HTTPS&#xff0c;它们的区别和联系 HTTP和HTTPS之间不同点 尽管HTTP和HTTPS在安全性方面存在差异&#xff0c;但它们仍然共享许多相同的基本特征和功能。这些相同点使得HTTP成为广泛应用的标准协议&#xff0c;并且HTTPS作为更安全的替代方案被广泛采用。HTTP…

npm yarn pnpm 命令集

npm 安装依赖 npm install 安装某个依赖 npm install xxx7.6.3 安装到全局&#xff08;dependencies&#xff09; npm install xxx7.6.3 -S 安装到线下&#xff08;devDependencies&#xff09; npm install xxx7.6.3 -D 卸载某个依赖 npm uninstall xxx 卸载全局依…

Codeforces EDU 151 Div.2

文章目录 A. Forbidden IntegerB. Come TogetherC. Strong PasswordD. Rating SystemE. Boxes and Balls A. Forbidden Integer Problem - A - Codeforces 给定整数n&#xff0c;从1~k中选择除了x的数&#xff0c;使这些数之和为n&#xff0c;每个数可以选择无限次 爆搜&…

[Vue]解决npm run dev报错node:internal/modules/cjs/loader:1031 throw err;

解决: 有2中方法&#xff0c;建议先尝试第一种&#xff0c;不行再第二种 第一种: 重新安装依赖环境 删除项目的node_modules文件夹&#xff0c;重新执行 # 安装依赖环境 npm install# 运行 npm run dev 我只用了第一种方法就可以了 &#xff0c;第二种方法从别的博主那看到…

【Java 动态数据统计图】动态数据统计思路案例(动态,排序,数组)二(113)

需求&#xff1a; 有一个List<Map<String.Object>>,存储了区域的数据&#xff0c; 数据是根据用户查询条件进行显示的&#xff1b;所以查询的数据是动态的&#xff1b;按区域维度统计每个区域出现的次数&#xff0c;并且按照次数的大小排序&#xff08;升序&#…

最新ChatGPT网站AI系统源码+详细图文搭建教程/支持GPT4.0/AI绘画/H5端/Prompt知识库/

一、前言 SparkAi系统是基于国外很火的ChatGPT进行开发的Ai智能问答系统。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。 那么如何搭建部署AI创作ChatGPT&#xff1f;小编这里写一个详细图文教程吧&#xff01…

从 Ansible Galaxy 使用角色

从 Ansible Galaxy 使用角色 根据下列要求&#xff0c;创建一个名为 /home/curtis/ansible/roles.yml 的 playbook &#xff1a; playbook 中包含一个 play&#xff0c; 该 play 在 balancers 主机组中的主机上运行并将使用 balancer 角色。 此角色配置一项服务&#xff0c;以…

Docker容器:docker镜像的创建及dockerfile

Docker容器&#xff1a;docker镜像的创建及dockerfile案例 一.docker镜像的三种创建方法 创建镜像有三种方法&#xff1a;基于现有镜像创建、基于本地模板创建及基于dockerfile创建 1.基于现有镜像创建 1.1 启动镜像 #首先启动一个镜像&#xff0c;在容器里做修改 docker …

SpringBoot常用注解-@PathVariable、@RequestParam 、@RequestBody

目录 PathVariable RequestParam RequestBody PathVariable PathVariable 获取url中的数据&#xff0c;绑定路径中的占位符参数到方法参数变量中&#xff0c;get或者post方式都可以&#xff0c;如果URL中无参数&#xff0c;将会出错 例如获取/login/id/name中的id值和name值 …

Linux网络编程:多进程 多线程_并发服务器

文章目录&#xff1a; 一&#xff1a;wrap常用函数封装 wrap.h wrap.c server.c封装实现 client.c封装实现 二&#xff1a;多进程process并发服务器 server.c服务器 实现思路 代码逻辑 client.c客户端 三&#xff1a;多线程thread并发服务器 server.c服务器 实现…

途乐证券|定增募资是什么意思?

作为融资手法之一&#xff0c;定增募资在企业中被广泛运用。但一般投资者对此或许不太了解&#xff0c;只知道它是一种融资手法。那么&#xff0c;定增募资到底是什么意思呢&#xff1f; 一、什么是定增募资&#xff1f; 定增募资即定向增发股票募集资金&#xff0c;是新股票发…