本地代理

当请求到来时应用上下文和程序上下文被推入本地栈中,全局变量current_app,request,g,session都可以使用了。以current_app为例,current_app代表的是app这个程序实例,但和app并不是同一个类型。current_app和app都有同样的功能,但是current_app和app不是一个对象。

from flask import Flask, current_app

app = Flask(__name__)

@app.route('/')
def hello_world():
print(f"{app} {type(app)}")
print(f"{current_app} {type(current_app)}")
return f"Hello world!" if __name__ == '__main__':
app.run()
<Flask 'flask_demo'>  <class 'flask.app.Flask'>
<Flask 'flask_demo'> <class 'werkzeug.local.LocalProxy'>

可以看出app和current_app都是flask的实例,但是两者的类型是不一样的。app就是flask实例本尊,是真的美猴王,而current_app是werkzeug模块里的本地代理对象,一个假美猴王。

为了探究这个问题,可以从current_app的定义入手。

从current_app的定义来就能知道,不光是current_app是本地代理对象,request,session,g等都是代理对象。

def _lookup_req_object(name):
top = _request_ctx_stack.top
if top is None:
raise RuntimeError(_request_ctx_err_msg)
return getattr(top, name) def _lookup_app_object(name):
top = _app_ctx_stack.top
if top is None:
raise RuntimeError(_app_ctx_err_msg)
return getattr(top, name) def _find_app():
top = _app_ctx_stack.top
if top is None:
raise RuntimeError(_app_ctx_err_msg)
return top.app _request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack() current_app = LocalProxy(_find_app)
request = LocalProxy(partial(_lookup_req_object, 'request'))
session = LocalProxy(partial(_lookup_req_object, 'session'))
g = LocalProxy(partial(_lookup_app_object, 'g'))

这里出现一个重要的概念本地代理,首先要搞明白什么是本地代理。

LocalProxy 介绍

LocalProxy 中文本地代理,和前面介绍的本地线程和本地栈类似,都可以根据线程隔离变量,同时还有代理的功能。

代理在生活中及其常见,比如现在的美团跑腿,你上班时间时间需要送一份文件给朋友,自己又抽不开身,这时可以预约一个全城送,付钱让他给你送文件。这个代送小哥就是一个代理。

广义的代理就是访问对象无法直接访问目标对象,代理对象作为中介,将访问传递给目标对象。

不使用代理

localstack获取栈顶元素的方法就是通过一个函数返回localstack的top。current_app的定义中的_find_app就是获取栈顶元素的函数。首先模拟不使用代理的方法来获取栈顶元素。

from werkzeug.local import LocalStack, LocalProxy
test_stack = LocalStack()
test_stack.push({'abc': '123'}) def get_stack_top():
return test_stack.top item = get_stack_top()
print(item) # 有新的元素入栈
test_stack.push({'abc': '1234'})
print(item)
{'abc': '123'}
{'abc': '123'}

当调用get_stack_top时,获取的最新的栈顶元素item。有元素入栈之后,item就不再是栈顶元素了。根据flask中current_app的使用,无论何时current_app, 都是获取栈顶元素。所以需要再次调用函数去获取栈顶元素。

使用本地代理

使用本地代理就不需要每次调用函数去获取栈顶元素,可以做到在app1入栈时current_app栈顶是app1,app2入栈时栈顶是app2。

from werkzeug.local import LocalStack, LocalProxy
test_stack = LocalStack()
test_stack.push({'abc': '123'}) def get_stack_top():
return test_stack.top item = LocalProxy(get_stack_top)
print(item) # 当栈发生变化时,再次使用使用代理对象,仍然可以获取到栈顶元素。
# 原理时每次访问item时,localproxy都会调用get_stack_top去获取栈顶
test_stack.push({'abc': '1234'})
print(item)
{'abc': '123'}
{'abc': '1234'}

将获取栈顶元素的函数传入LocalProxy,然后访问LocalProxy实例item,每次都能获取栈顶元素,而不需要再次调用获取栈顶的函数get_stack_top。原理在于每次去访问item时,本地代理都是调用get_stack_top函数去获取栈顶,相当于帮我们去调用了函数。

小结

本地代理的使用是传入要获取栈顶的函数,当每次访问本地代理对象时,本地代理调用函数获取最新栈顶,减少了业务中调用函数的过程,是获取栈顶元素的一种优雅方法。

上下文中的4种全局变量都是本地代理对象,任何时候访问这4中变量时,本地代理能返回最新的栈顶元素。

系列总结

写到这里就将Flask中最核心的请求处理介绍完了。这个系列由浅入深,分别介绍了:

  1. 最简单Flask程序
  2. Flask依赖的核心模块werkzeug
  3. Flask请求数据的优雅传递
  4. Flask中本地栈的使用
  5. Flask中本地代理的使用

可以这个主题是Flask最值得探讨赏析的技术之一,通过这个系列我学习到一些全新的知识,如全局变量的线程隔离,代理模式的优雅,Flask请求和非请求场景下业务的统一等。能够弄明白这些知识虽然也花费了很多时间但是很值得。所谓山有路勤为径,学海无涯苦作舟。

Flask中本地代理的使用的更多相关文章

  1. Flask中本地栈的使用

    4种上下文变量 承接上一篇内容.当一个请求到来时,除了request被封装成全局变量之外,还有三个变量也是同样被封装成全局变量,那就是current_app.g.session.上面4个变量之所以能够 ...

  2. Flask中的ThreadLocal本地线程,上下文管理

    先说一下和flask没有关系的: 我们都知道线程是由进程创建出来的,CPU实际执行的也是线程,那么线程其实是没有自己独有的内存空间的,所有的线程共享进程的资源和空间,共享就会有冲突,对于多线程对同一块 ...

  3. Flask中全局变量的实现

    我们都知道在Flask中g,request,session和request是作为全局对象来提供信息的,既然是全局的又如何保持线程安全呢,接下来我们就看看flask是如何做到这点的.在源码中的ctx.p ...

  4. Python框架学习之Flask中的视图及路由

    在前面一讲中我们学习如何创建一个简单的Flask项目,并做了一些简单的分析.接下来在这一节中就主要来讲讲Flask中最核心的内容之一:Werkzeug工具箱.Werkzeug是一个遵循WSGI协议的P ...

  5. flask中的蓝图与红图

    内容: 1.flask中的蓝图 2.flask子域名实现 3.flask中的红图 1.flask中的蓝图 一个大型项目中视图比较多,如果仅仅是写在app.py中不方便管理,蓝图就可以做到分功能分目录结 ...

  6. flask中cookie和session介绍

    flask中cookie和session介绍 一.cookie: 在网站中,http请求是无状态的.也就是说即使第一次和服务器连接后并且登录成功后,第二次请求服务器依然不能知道当前请求是哪个用户.co ...

  7. 将 flask 中的 session 存储到 SQLite 数据库中

    将 flask 中的 session 存储到 SQLite 数据库中 使用 flask 构建服务器后端时,常需要在浏览器端存储 cookie 用于识别不同用户,根据不同的 cookie 判断出当前请求 ...

  8. 3 微信开发本地代理环境的搭建--实现将内网ip映射到外网

    微信公众号的开发,要搭建网站,并且随时都有可能修改网站内容进行调试,这就需要临时外网能返回本地开发环境搭建的项目进行测试,即内网映射到公网,但是好多开发者没有自己的域名和服务器,这里我们先来搭建一个本 ...

  9. flask通过nginx代理后base_url拿不到正确的url_scheme2016-04-14 12:31

    http://www.axiaoxin.com/article/210/ Nginx配置了https请求后,用户发起https请求时首先和Nginx建立连接,完成SSL握手,而后Nginx作为代理是以 ...

  10. vue-cli 本地代理 造成session丢失 而登录不上去 解决办法

    本地代理造成session丢失,登录不成功,是由于代理配置造成的 devServer: { port: 8000, proxy:{ '/qiantai':{ target:'线上地址/qiantai' ...

随机推荐

  1. webpack配置局域网访问项目

    要配置webpack允许局域网访问项目,你需要做以下几个步骤:   1. 在webpack配置文件中,找到devServer选项,并设置其属性`host`为`0.0.0.0`.这将允许其他设备通过局域 ...

  2. 查看API官方文档

    盛年不重来,一日难再晨.及时宜自勉,岁月不待人.   学习一门语言, 了解其开发文档必不可少.开发文档就是我们在编程开发.维护.升级过程中的参考最全面.最权威的资料.我认为就是开发者为后人方便理解留下 ...

  3. 微信小程序直播接入指南

    微信小程序直播接入指南 小程序直播组件接入指引 一.简介 小程序直播,是微信提供给小程序开发者的直播组件.通过调用该组件,商家可以在小程序中实现直播功能. 按下面的使用说明接入,在你的小程序中引入直播 ...

  4. 【外包杯】【报错】(表面解决实际未解决)微信小程序报错:[渲染层错误] TypeError: Cannot read property ‘$$‘ of undefined

    半解不解吧,反正实现了就行 渲染层出错,滑动图片组件无法显示,(swiper是轮播图插件,因此错误应该出现在swiper渲染中) 可以这样移动,但是没有图片 我觉得是路径的问题 兄弟们,目前没有解决接 ...

  5. Axure实战应用:Axure设计可视化大屏!

    Axure是一款功能强大的原型设计工具,可以用于设计可视化大屏.设计一个有效的可视化大屏需要考虑多个方面,包括布局规划.信息展示.交互设计等. 以下是一个详细的描述,希望对你有所帮助. 第一部分:可视 ...

  6. typora写作

    平时写博客,一般采用typora,但是字体颜色和上传到博客园的图片大小和居中问题,总是很糟糕,偶然发现输入法里面还有自定义的短语,能够解决这个问题. <p><img src=&quo ...

  7. [ABC232G] Modulo Shortest Path

    Problem Statement We have a directed graph with $N$ vertices, called Vertex $1$, Vertex $2$, $\ldots ...

  8. Java项目整合短信验证码

    一.开通短信服务 本来想整合阿里云短信服务的,可是签名一直审核不过,所以在阿里云的云市场找到了一个替代产品(sddx) 接下来小伙伴们按照自己的经济实力购买或者用免费的5条(我就是用免费的5条了) 购 ...

  9. 聊聊kube-scheduler如何完成调度和调整调度权重

    本文分享自华为云社区<kube-scheduler如何完成调度和调整调度权重>,作者: 可以交个朋友. 一.概述 Kube-scheduler作为k8s集群的默认调度器,它监听(watch ...

  10. Pix4Dmapper空间三维模型的应用实例:GIS选址分析

      本文介绍基于无人机影像建模完成后的结果,利用ArcMap软件进行空间选址分析,从而实现空间三维模型应用的方法. 目录 1 空间分析目标确立 2 基于基本约束条件的选址求解 2.1 坡度计算与提取 ...