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 信号机制的更多相关文章

  1. Inside Flask - signal 信号机制

    Inside Flask - signal 信号机制 singal 在平常的 flask web 开发过程中较少接触到,但对于使用 flask 进行框架级别的开发时,则必须了解相关的工作机制.flas ...

  2. Flask笔记:信号机制

    Flask中有内置的一些信号,也可以通过三方库blinker自定义信号,其实Flask内置的信号也是优先使用的blinker库,如果没有安装blinker才会使用自定义的信号机制.可以通过点击任意导入 ...

  3. 信号(Django信号、Flask信号、Scrapy信号)

    简介 Django.Flask.scrapy都包含了一个“信号分配器”,使得当一些动作在框架的其他地方发生的时候,解耦的应用可以得到提醒. 通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒 ...

  4. linux信号机制与python信号量

    1.信号本质 软中断信号(signal,又简称为信号)用来通知进程发生了异步事件.在软件层次上是对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的.信号是进程间 ...

  5. linux信号机制 - 用户堆栈和内核堆栈的变化【转】

    转自:http://itindex.net/detail/16418-linux-%E4%BF%A1%E5%8F%B7-%E5%A0%86%E6%A0%88 此文只简单分析发送信号给用户程序后,用户堆 ...

  6. 利用linux信号机制调试段错误(Segment fault)

    在实际开发过程中,大家可能会遇到段错误的问题,虽然是个老问题,但是其带来的隐患是极大的,只要出现一次,程序立即崩溃中止.如果程序运行在PC中,segment fault的调试相对比较方便,因为可以通过 ...

  7. Django的信号机制

    Django提供一种信号机制.其实就是观察者模式,又叫发布-订阅(Publish/Subscribe) .当发生一些动作的时候,发出信号,然后监听了这个信号的callback函数就会执行. Djang ...

  8. linux中的信号机制

    概述 Linux信号机制是在应用软件层次上对中断机制的一种模拟,信号提供了一种处理异步事件的方法,例如,终端用户输入中断键(ctrl+c),则会通过信号机制停止一个程序[1]. 这其实就是向那个程序( ...

  9. flask信号使用

    flask信号: 安装: flask中的信号使用的是一个第三方插件,叫做blinker.通过pip list看一下,如果没有安装,通过以下命令即可安装blinker: pip install blin ...

随机推荐

  1. “浪潮杯”山东省第五届ACM大学生程序设计竞赛(总结贴)

    第一次參加省赛有点小激动,尽管是作为打星队參赛,但心情却是上下起伏. 5月9号晚上11点多到威海,有点略冷.可是空气比淄博好多了,大家到了旅馆的时候都非常晚了,抱怨了一下三星级的酒店的待遇,喝杯咖啡早 ...

  2. iOS-WKWebView使用

    使用代码:可直接粘贴到自己项目中使用 .h #import "BaseViewController.h" @interface LinkNewsController : BaseV ...

  3. laravel 控制器构造方法注入request对象

    IndexController: <?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Http\ ...

  4. js基础---->js中的消息框

    可以在JavaScript 中创建三种消息框:警告框.确认框.提示框.今天我们就这几个框做一个介绍.我们笑着说再见,却深知再见遥遥无期. javascript消息框 一.警告框:警告框经常用于确保用户 ...

  5. JS-元素大小深入学习-offset、client、scroll等学习研究笔记

    一些属性和方法,在dom中没有规定如何确定页面中元素大小的情况下诞生... 1.偏移量(offset dimension) 测试代码: <!DOCTYPE html> <html&g ...

  6. hihocoder [Offer收割]编程练习赛14 剑刃风暴

    题目4 : 剑刃风暴 时间限制:20000ms 单点时限:2000ms 内存限制:256MB 描述 主宰尤涅若拥有一招非常厉害的招式——剑刃风暴,“无论是战士还是法师,都害怕尤涅若的武士刀剑技”. 现 ...

  7. web图片100%宽度自适应,高度不塌陷

    一般在web端图片100%自适应,在页面加载的时候存在高度塌陷的问题 解决这个问题其实很简单,用padding-top设置百分比值来实现自适应,公式如下 padding-top = (Image He ...

  8. ios8 gps定位不好用

    这样让iOS8正常使用定位功能呢? <1>你需要在info.plist表里面添加两条变量 在Info.plist中加入两个缺省没有的字段 NSLocationAlwaysUsageDesc ...

  9. 一个Activity中使用两个layout实例

    package com.sbs.aas2l; import android.app.Activity; import android.os.Bundle; import android.view.Vi ...

  10. 补课:PageRank

    最近连续听到PageRank算法,久闻其名,不闻其详,心里虚得很,今儿补补课. PageRank算法的网络资料非常全面,毕竟是将近二十年的经典算法,算法细节可以参考文末链接,这里简单说说我的理解. P ...