了解Flask 信号机制
Flask框架中的信号基于blinker,其主要就是让开发者可是在flask请求过程中定制一些用户行为。
- pip3 install blinker
1. 内置信号
- request_started = _signals.signal('request-started') # 请求到来前执行
- request_finished = _signals.signal('request-finished') # 请求结束后执行
- before_render_template = _signals.signal('before-render-template') # 模板渲染前执行
- template_rendered = _signals.signal('template-rendered') # 模板渲染后执行
- got_request_exception = _signals.signal('got-request-exception') # 请求执行出现异常时执行
- request_tearing_down = _signals.signal('request-tearing-down') # 请求执行完毕后自动执行(无论成功与否)
- appcontext_tearing_down = _signals.signal('appcontext-tearing-down')# 请求上下文执行完毕后自动执行(无论成功与否)
- appcontext_pushed = _signals.signal('appcontext-pushed') # 请求上下文push时执行
- appcontext_popped = _signals.signal('appcontext-popped') # 请求上下文pop时执行
- message_flashed = _signals.signal('message-flashed') # 调用flask在其中添加数据时,自动触发
2. 源码示例
- class Flask(_PackageBoundObject):
- def full_dispatch_request(self):
- self.try_trigger_before_first_request_functions()
- try:
- # ############### 触发request_started 信号 ###############
- request_started.send(self)
- rv = self.preprocess_request()
- if rv is None:
- rv = self.dispatch_request()
- except Exception as e:
- rv = self.handle_user_exception(e)
- response = self.make_response(rv)
- response = self.process_response(response)
- # ############### request_finished 信号 ###############
- request_finished.send(self, response=response)
- return response
- def wsgi_app(self, environ, start_response):
- ctx = self.request_context(environ)
- ctx.push()
- error = None
- try:
- try:
- response = self.full_dispatch_request()
- except Exception as e:
- error = e
- response = self.make_response(self.handle_exception(e))
- return response(environ, start_response)
- finally:
- if self.should_ignore_error(error):
- error = None
- ctx.auto_pop(error)
request_started
- 同上
request_finished
- def render_template(template_name_or_list, **context):
- """Renders a template from the template folder with the given
- context.
- :param template_name_or_list: the name of the template to be
- rendered, or an iterable with template names
- the first one existing will be rendered
- :param context: the variables that should be available in the
- context of the template.
- """
- ctx = _app_ctx_stack.top
- ctx.app.update_template_context(context)
- return _render(ctx.app.jinja_env.get_or_select_template(template_name_or_list),
- context, ctx.app)
- def _render(template, context, app):
- """Renders the template and fires the signal"""
- # ############### before_render_template 信号 ###############
- before_render_template.send(app, template=template, context=context)
- rv = template.render(context)
- # ############### template_rendered 信号 ###############
- template_rendered.send(app, template=template, context=context)
- return rv
before_render_template
- 同上
template_rendered
- class Flask(_PackageBoundObject):
- def handle_exception(self, e):
- exc_type, exc_value, tb = sys.exc_info()
- # ############### got_request_exception 信号 ###############
- got_request_exception.send(self, exception=e)
- handler = self._find_error_handler(InternalServerError())
- if self.propagate_exceptions:
- # if we want to repropagate the exception, we can attempt to
- # raise it with the whole traceback in case we can do that
- # (the function was actually called from the except part)
- # otherwise, we just raise the error again
- if exc_value is e:
- reraise(exc_type, exc_value, tb)
- else:
- raise e
- self.log_exception((exc_type, exc_value, tb))
- if handler is None:
- return InternalServerError()
- return handler(e)
- def wsgi_app(self, environ, start_response):
- ctx = self.request_context(environ)
- ctx.push()
- error = None
- try:
- try:
- response = self.full_dispatch_request()
- except Exception as e:
- error = e
- # 这里这里这里这里这里这里这里这里这里这里这里这里 #
- response = self.make_response(self.handle_exception(e))
- return response(environ, start_response)
- finally:
- if self.should_ignore_error(error):
- error = None
- ctx.auto_pop(error)
got_request_exception
- class AppContext(object):
- def push(self):
- """Binds the app context to the current context."""
- self._refcnt += 1
- if hasattr(sys, 'exc_clear'):
- sys.exc_clear()
- _app_ctx_stack.push(self)
- # ############## 触发 appcontext_pushed 信号 ##############
- appcontext_pushed.send(self.app)
- def pop(self, exc=_sentinel):
- """Pops the app context."""
- try:
- self._refcnt -= 1
- if self._refcnt <= 0:
- if exc is _sentinel:
- exc = sys.exc_info()[1]
- # ############## 触发 appcontext_tearing_down 信号 ##############
- self.app.do_teardown_appcontext(exc)
- finally:
- rv = _app_ctx_stack.pop()
- assert rv is self, 'Popped wrong app context. (%r instead of %r)' \
- % (rv, self)
- # ############## 触发 appcontext_popped 信号 ##############
- appcontext_popped.send(self.app)
- class RequestContext(object):
- def push(self):
- top = _request_ctx_stack.top
- if top is not None and top.preserved:
- top.pop(top._preserved_exc)
- app_ctx = _app_ctx_stack.top
- if app_ctx is None or app_ctx.app != self.app:
- # ####################################################
- app_ctx = self.app.app_context()
- app_ctx.push()
- self._implicit_app_ctx_stack.append(app_ctx)
- else:
- self._implicit_app_ctx_stack.append(None)
- if hasattr(sys, 'exc_clear'):
- sys.exc_clear()
- _request_ctx_stack.push(self)
- # Open the session at the moment that the request context is
- # available. This allows a custom open_session method to use the
- # request context (e.g. code that access database information
- # stored on `g` instead of the appcontext).
- self.session = self.app.open_session(self.request)
- if self.session is None:
- self.session = self.app.make_null_session()
- class Flask(_PackageBoundObject):
- def wsgi_app(self, environ, start_response):
- ctx = self.request_context(environ)
- ctx.push()
- error = None
- try:
- try:
- response = self.full_dispatch_request()
- except Exception as e:
- error = e
- response = self.make_response(self.handle_exception(e))
- return response(environ, start_response)
- finally:
- if self.should_ignore_error(error):
- error = None
- ctx.auto_pop(error)
- def pop(self, exc=_sentinel):
- app_ctx = self._implicit_app_ctx_stack.pop()
- try:
- clear_request = False
- if not self._implicit_app_ctx_stack:
- self.preserved = False
- self._preserved_exc = None
- if exc is _sentinel:
- exc = sys.exc_info()[1]
- # ################## 触发 request_tearing_down 信号 ##################
- self.app.do_teardown_request(exc)
- # If this interpreter supports clearing the exception information
- # we do that now. This will only go into effect on Python 2.x,
- # on 3.x it disappears automatically at the end of the exception
- # stack.
- if hasattr(sys, 'exc_clear'):
- sys.exc_clear()
- request_close = getattr(self.request, 'close', None)
- if request_close is not None:
- request_close()
- clear_request = True
- finally:
- rv = _request_ctx_stack.pop()
- # get rid of circular dependencies at the end of the request
- # so that we don't require the GC to be active.
- if clear_request:
- rv.request.environ['werkzeug.request'] = None
- # Get rid of the app as well if necessary.
- if app_ctx is not None:
- # ####################################################
- app_ctx.pop(exc)
- assert rv is self, 'Popped wrong request context. ' \
- '(%r instead of %r)' % (rv, self)
- def auto_pop(self, exc):
- if self.request.environ.get('flask._preserve_context') or \
- (exc is not None and self.app.preserve_context_on_exception):
- self.preserved = True
- self._preserved_exc = exc
- else:
- self.pop(exc)
request_tearing_down
- 同上
request_tearing_down
- 同上
appcontext_tearing_down
- 同上
appcontext_pushed
- 同上
appcontext_popped
- def flash(message, category='message'):
- """Flashes a message to the next request. In order to remove the
- flashed message from the session and to display it to the user,
- the template has to call :func:`get_flashed_messages`.
- .. versionchanged:: 0.3
- `category` parameter added.
- :param message: the message to be flashed.
- :param category: the category for the message. The following values
- are recommended: ``'message'`` for any kind of message,
- ``'error'`` for errors, ``'info'`` for information
- messages and ``'warning'`` for warnings. However any
- kind of string can be used as category.
- """
- # Original implementation:
- #
- # session.setdefault('_flashes', []).append((category, message))
- #
- # This assumed that changes made to mutable structures in the session are
- # are always in sync with the session object, which is not true for session
- # implementations that use external storage for keeping their keys/values.
- flashes = session.get('_flashes', [])
- flashes.append((category, message))
- session['_flashes'] = flashes
- # ############### 触发 message_flashed 信号 ###############
- message_flashed.send(current_app._get_current_object(),
- message=message, category=category)
message_flashed
3. 执行流程
- a. before_first_request
- b. 触发 request_started 信号
- c. before_request
- d. 模板渲染
- 渲染前的信号 before_render_template.send(app, template=template, context=context)
- rv = template.render(context) # 模板渲染
- 渲染后的信号 template_rendered.send(app, template=template, context=context)
- e. after_request
- f. session.save_session()
- g. 触发 request_finished信号
- 如果上述过程出错:
- 触发错误处理信号 got_request_exception.send(self, exception=e)
- h. 触发信号 request_tearing_down
4. 自定义信号
- #!/usr/bin/env python
- # -*- coding:utf-8 -*-
- from flask import Flask, current_app, flash, render_template
- from flask.signals import _signals
- app = Flask(import_name=__name__)
- # 自定义信号
- xxxxx = _signals.signal('xxxxx')
- def func(sender, *args, **kwargs):
- print(sender)
- # 自定义信号中注册函数
- xxxxx.connect(func)
- @app.route("/x")
- def index():
- # 触发信号
- xxxxx.send('123123', k1='v1')
- return 'Index'
- if __name__ == '__main__':
- app.run()
了解Flask 信号机制的更多相关文章
- Inside Flask - signal 信号机制
Inside Flask - signal 信号机制 singal 在平常的 flask web 开发过程中较少接触到,但对于使用 flask 进行框架级别的开发时,则必须了解相关的工作机制.flas ...
- Flask笔记:信号机制
Flask中有内置的一些信号,也可以通过三方库blinker自定义信号,其实Flask内置的信号也是优先使用的blinker库,如果没有安装blinker才会使用自定义的信号机制.可以通过点击任意导入 ...
- 信号(Django信号、Flask信号、Scrapy信号)
简介 Django.Flask.scrapy都包含了一个“信号分配器”,使得当一些动作在框架的其他地方发生的时候,解耦的应用可以得到提醒. 通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒 ...
- linux信号机制与python信号量
1.信号本质 软中断信号(signal,又简称为信号)用来通知进程发生了异步事件.在软件层次上是对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的.信号是进程间 ...
- linux信号机制 - 用户堆栈和内核堆栈的变化【转】
转自:http://itindex.net/detail/16418-linux-%E4%BF%A1%E5%8F%B7-%E5%A0%86%E6%A0%88 此文只简单分析发送信号给用户程序后,用户堆 ...
- 利用linux信号机制调试段错误(Segment fault)
在实际开发过程中,大家可能会遇到段错误的问题,虽然是个老问题,但是其带来的隐患是极大的,只要出现一次,程序立即崩溃中止.如果程序运行在PC中,segment fault的调试相对比较方便,因为可以通过 ...
- Django的信号机制
Django提供一种信号机制.其实就是观察者模式,又叫发布-订阅(Publish/Subscribe) .当发生一些动作的时候,发出信号,然后监听了这个信号的callback函数就会执行. Djang ...
- linux中的信号机制
概述 Linux信号机制是在应用软件层次上对中断机制的一种模拟,信号提供了一种处理异步事件的方法,例如,终端用户输入中断键(ctrl+c),则会通过信号机制停止一个程序[1]. 这其实就是向那个程序( ...
- flask信号使用
flask信号: 安装: flask中的信号使用的是一个第三方插件,叫做blinker.通过pip list看一下,如果没有安装,通过以下命令即可安装blinker: pip install blin ...
随机推荐
- Java输入输出流(2)
6. Java.IO流类库 1. io流的四个基本类 java.io包中包括了流式I/O所须要的全部类. 在java.io包中有四个基本类:InputStream.OutputStream及Reade ...
- os.path模块【python】
os.path.abspath(path) #返回绝对路径 os.path.basename(path) #返回文件名 os.path.commonprefix(list) #返回list(多个路径) ...
- js方法随机抽取n个随机数
function getImageRandomPosition(){ do { var n = Math.floor(Math.random() * 12);//n为随机出现的0-11之内的数值 fo ...
- Gamma编码及Delta编码概述
一.Elias Gamma Coding 即Gamma编码,是一种对正整数进行编码的统一编码,由Peter Elias发明.适用于预先无法获知最大编码整数的情况,而且小整数出现频率高,大整数出现频率低 ...
- 《转》python学习(6)序列类型-字符串
转自 http://www.cnblogs.com/BeginMan/archive/2013/06/08/3125502.html 二.序列类型 包含字符串.列表.元祖.模式都一样,举一反三即可.如 ...
- python初学总结(二)
(1)字典 字典是一种映射关系:键(key),值(value),key-value对 创建字典的方式:直接创建和利用dict函数创建 >>> aInfo = {'Wangdachui ...
- 解决提示“配色方案已更改为Windows7 Basic”
WIN7是很多用户都用过的系统,是由微软推出的.下面就说一个小技巧. 如何解决Win7系统提示:“配色方案已更改为Windows 7 Basic”解决方案. 更改Win7配色方案 首先,右击桌面空 ...
- 【BZOJ2661】[BeiJing wc2012]连连看 最大费用流
[BZOJ2661][BeiJing wc2012]连连看 Description 凡是考智商的题里面总会有这么一种消除游戏.不过现在面对的这关连连看可不是QQ游戏里那种考眼力的游戏.我们的规则是,给 ...
- svn-maven-tomcat自动发布脚本
#!/bin/sh #svn-maven-tomcat自动发布脚本 #变量设置 svnpath=svn://10.60.10.120/研发部/xx-maven svnusername=xxx svnp ...
- PHP中文字数限制:中文字符串截取(mb_substr)
一.中文截取:mb_substr() mb_substr( $str, $start, $length, $encoding ) $str,需要截断的字符串 $start,截断开始处,起始处为0 $l ...