一、flask请求上下文源码解读

  通过上篇源码分析( ---Flask中的CBV和上下文管理--- ),我们知道了有请求发来的时候就执行了app(Flask的实例化对象)的__call__方法,而__call__方法返回了app的wsgi_app(environ, start_response)方法的执行结果,而wsgi_app方法中有这样一句话:ctx = self.request_context(environ),还分析除了ctx是RequestContext类的实例化对象,而且ctx中含有有本次请求的request对象和session对象。

  接下来我们重点分析flask是如何做到把request对象当成全局变量,而又保证了数据安全,即请求信息互不影响的。

1、flask请求上文源码解读

  上篇我们分析到了如何得到RequestContext实例化对象ctx,接下来ctx对象执行push方法,如下:

    

  RequestContext类中的push方法源码如下:

    

  _request_ctx_stack是LocalStack类的实例化对象:

     

  LocalStack类中的__init__方法如下:

    

  Local类的__init__方法如下:

    

  get_ident是Local类所在文件中导入的一个方法名,该方法执行后会得到线程或协程ID,如下:

    

  LocalStack类中的top是一个属性方法,源码如下:

    

  下一步Local类中的__getattr__方法源码如下:

    

  到此,分析得出top = _request_ctx_stack.top中的top为None。

  接下来分析 _request_ctx_stack.push(self)做了什么?LocalStack类中的push方法源码如下:

    

  Local类中的__setattr__方法源码如下:

    

  因为rv.append(obj),所以最后LocalStack对象,即_request_ctx_stack对象字典化后如下:

  1.   {'_local':{'__storage__':{9527:{stack:[ctx]}}, '__ident_func__':get_ident}}
  2.   # 说明:9527假设是获取到的线程或者协程号,ctx包含request对象和session对象。

  到此,flask请求上文结束,也就是完成了将一个request和session对象存储到某个地方。

2、下文

  我们知道flask的request对象和session对象是全局变量,上文已经解读了如何存储。接下来解读如何在保证数据安全的情况下取出来,即只取到自己的请求信息而非其他人的。

  我们还知道request对象中存储了很多信息,如request.method存储请求方式、request.json存储json标准字符串等等。下面以request.method为例,分析如何得到请求方式信息。

  导入request方式如下:

  1.   from flask import request

  源码如下:

    

  LocalProxy类的__init__方法如下:

    

  偏函数中的原函数_lookup_req_object源码如下:

    

  当执行request.method的时候,执行LocalProxy的__getattr__方法,源码如下:

    

  查看类LocalProxy中的_get_current_object方法是如何得到本次请求的request对象,源码如下:

    

  至此,我们已经分析出了如何得到本次请求的request对象,从而取出request对象中的相关信息。

二、http聊天室(单聊/群聊)

1、准备知识

  http协议特点:短连接,无状态保存;

  轮询:前后端一秒交互多次,压力极大,并且消耗带宽,资源浪费极其严重;

  长轮询:即让服务器保存我的一个连接状态,用于快速传递消息,节省带宽,释放压力,数据实时性强;

  长连接:服务端及客户端节省极大的资源,能保证数据实时性;

  带宽:1Mbps  = 128KB/s

2、http聊天室

  准备工作:下载gevent-websocket模块

  1. pip3 install gevent-websocket

  代码示例:

  manage.py代码:

  1.   from flask import Flask, request, render_template
  2.   from geventwebsocket.handler import WebSocketHandler
  3.   from geventwebsocket.websocket import WebSocket # 提示用
  4.   from gevent.pywsgi import WSGIServer
  5.   import json
  6.  
  7.   app = Flask(__name__)
  8.  
  9.   user_socket_dict = {} # 用户字典
  10.  
  11.   @app.route('/ws/<username>')
  12.   def ws(username):
  13.     print(request.environ) # 有个wsgi.websocket,通过它可以发消息
  14.     user_socket = request.environ.get('wsgi.websocket') #type:WebSocket
  15.     if user_socket:
  16.       user_socket_dict[username] = user_socket
  17.     print(user_socket_dict)
  18.     while 1:
  19.       msg = user_socket.receive()
  20.       msg_dict = json.loads(msg)
  21.       msg_dict['from_user'] = username
  22.       to_user = msg_dict.get('to_user')
  23.       # chat = msg_dict.get('msg')
  24.       u_socket = user_socket_dict.get(to_user) #type:WebSocket
  25.       u_socket.send(json.dumps(msg_dict))
  26.  
  27.   @app.route('/')
  28.   def index():
  29.     return render_template('ws.html')
  30.  
  31.   if __name__ == '__main__':
  32.     http_serv = WSGIServer(('0.0.0.0',9527), app, handler_class=WebSocketHandler)
  33.     http_serv.server_forever()

  ws.html代码:

  1.   <!DOCTYPE html>
  2.   <html lang="en">
  3.   <head>
  4.     <meta charset="UTF-8">
  5.     <title>Title</title>
  6.   </head>
  7.   <body>
  8.  
  9.     <input id="username"type="text"><button onclick="login()">登录聊天室</button>
  10.  
  11.     给<input id="to_user"type="text">
  12.  
  13.     <input id="msg"type="text"><button onclick="send_msg()">发送</button>
  14.  
  15.     <div id="chat_list"style="width:500px; height:500px; border:1px solid red;"></div>
  16.  
  17.   </body>
  18.  
  19.   <script type="text/javascript">
  20.  
  21.   var ws = null; // 因其他函数也可能会用到ws,所以不能放在某一个函数中
  22.  
  23.   function login() {
  24.     var username = document.getElementById('username').value;
  25.     var ws = new WebSocket('ws://192.168.13.172:9527/ws'+username); // ws请求协议
  26.     ws.onmessage = function (data) {
  27.       console.log(data.data);
  28.       var recv_msg = JSON.parse(data.data);
  29.       var ptag = document.createElement('p');
  30.       ptag.innerText = recv_msg.from_user + ':' + recv_msg.msg;
  31.       document.getElementById('caht_list').appendChild(ptag)
  32.     };
  33.   }
  34.  
  35.   function send_msg() {
  36.     var to_user = document.getElementById('to_user').value;
  37.     var msg = document.getElementById('msg').value;
  38.     var send_dict = {
  39.       'to_user':to_user,
  40.       'msg':msg
  41.     };
  42.     ws.send(JSON.stringify(send_dict));
  43.   }
  44.  
  45.   </script>
  46.  
  47.   </html>
 
 
 

flask的请求上下文源码解读的更多相关文章

  1. Flask(4)- flask请求上下文源码解读、http聊天室单聊/群聊(基于gevent-websocket)

    一.flask请求上下文源码解读 通过上篇源码分析,我们知道了有请求发来的时候就执行了app(Flask的实例化对象)的__call__方法,而__call__方法返回了app的wsgi_app(en ...

  2. flask 请求上下文源码(转)

    本篇阅读目录 一.flask请求上下文源码解读 二.http聊天室(单聊/群聊)- 基于gevent-websocket 回到顶部 转:https://www.cnblogs.com/li-li/p/ ...

  3. Flask系列10-- Flask请求上下文源码分析

    总览 一.基础准备. 1. local类 对于一个类,实例化得到它的对象后,如果开启多个线程对它的属性进行操作,会发现数据时不安全的 import time from threading import ...

  4. Flask框架 (四)—— 请求上下文源码分析、g对象、第三方插件(flask_session、flask_script、wtforms)、信号

    Flask框架 (四)—— 请求上下文源码分析.g对象.第三方插件(flask_session.flask_script.wtforms).信号 目录 请求上下文源码分析.g对象.第三方插件(flas ...

  5. Flask请求上下文源码讲解,简单的群聊单聊web

    请求上下文流程图 群聊html代码 <!DOCTYPE html> <html lang="en"> <head> <meta chars ...

  6. Flask核心机制--上下文源码剖析

    一.前言 了解过flask的python开发者想必都知道flask中核心机制莫过于上下文管理,当然学习flask如果不了解其中的处理流程,可能在很多问题上不能得到解决,当然我在写本篇文章之前也看到了很 ...

  7. flask请求上下文源码分析

    一.什么是上下文 每一段程序都有很多外部变量,只有像add这种简单的函数才是没有外部变量的,一旦你的一段程序有了外部变量,这段程序就不完整了,不能独立运行,你为了使他们能运行,就要给所有的外部变量一个 ...

  8. Flask请求和应用上下文源码分析

      flask的request和session设置方式比较新颖,如果没有这种方式,那么就只能通过参数的传递. flask是如何做的呢? 1:本地线程,保证即使是多个线程,自己的值也是互相隔离 1 im ...

  9. Flask源码解读--所有可扩展点

    一.前言 flask中有很多可扩展点(笔者这样称呼),其中包含了信号和请求钩子,这些信号和钩子有什么用呢?其主要作用用于帮助我们进行程序的耦合性,当然还可以让我们自定义一些行为.话不多说,通过阅读源码 ...

随机推荐

  1. C++输入和输出中进制问题

    默认下都是十进制 int i, j, k, l; cin>>oct>>i; //输入为八进制数 cin>>hex>>j; //输入为十六进制数 cin& ...

  2. sencha toucha获取 constructor中的数据

    config:{ tmp:null }, constructor : function(conf) { this.config.tmp=conf; } 添加配置属性,然后直接用 this.config ...

  3. DailyMasalaCMS升级记录

    手头上是一个比较老的工程,Jdk1.7 + Tomcat7.0 + Spring 3.x + Hibernate 3.x + Elasticseach 2.x 最近Elasticsearch升级,ja ...

  4. linux中shell脚本中系统预先定义的变量

    $0:脚本名称: $*:所有参数: $$:当前进程或者脚本的PID号: $!:后台运行的最后一个进程的PID号: $?:用于返回上一个命令是否成功.成功0,否则为非零: $#:参数个数: $@:所有参 ...

  5. void f(int(&amp;p)[3]){} 和void f(int(*p)[3]){}的差别

    #include<iostream> using namespace std; void f(int(&p)[3]){          cout<<p[0]<& ...

  6. 国内最受欢迎的7大API供应平台对比和介绍

    俗话说“巧妇难为无米之炊”,数据源就是数据产生价值中的那些大米.那大数据时代企业需要哪些数据呢?根据我个人理解我觉得可以大致分为以下几类: 1.(内部)企业自身业务生产经营环节产生的内部数据[包括销售 ...

  7. Odoo11 重大改变

    Table of Contents 新特性 Activity 项目子任务 组织架构 地址 域 widget 功能重构 Quant 份 procurement 补货 自动动作 动作绑定 去掉了stock ...

  8. ASP.NET MVC深入浅出系列(持续更新) ORM系列之Entity FrameWork详解(持续更新) 第十六节:语法总结(3)(C#6.0和C#7.0新语法) 第三节:深度剖析各类数据结构(Array、List、Queue、Stack)及线程安全问题和yeild关键字 各种通讯连接方式 设计模式篇 第十二节: 总结Quartz.Net几种部署模式(IIS、Exe、服务部署【借

    ASP.NET MVC深入浅出系列(持续更新)   一. ASP.NET体系 从事.Net开发以来,最先接触的Web开发框架是Asp.Net WebForm,该框架高度封装,为了隐藏Http的无状态模 ...

  9. uva 1493 - Draw a Mess(并查集)

    题目链接:uva 1493 - Draw a Mess 题目大意:给定一个矩形范围,有四种上色方式,后面上色回将前面的颜色覆盖,最后问9种颜色各占多少的区域. 解题思路:用并查集维护每一个位置相应下一 ...

  10. java 开发环境安装

    一.在mac上安装jdk 1. 下载Mac版本的JDK并安装      http://www.oracle.com/technetwork/java/javase/downloads/index.ht ...