flask的请求上下文源码解读
一、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对象字典化后如下:
{'_local':{'__storage__':{9527:{stack:[ctx]}}, '__ident_func__':get_ident}}
# 说明:9527假设是获取到的线程或者协程号,ctx包含request对象和session对象。
到此,flask请求上文结束,也就是完成了将一个request和session对象存储到某个地方。
2、下文
我们知道flask的request对象和session对象是全局变量,上文已经解读了如何存储。接下来解读如何在保证数据安全的情况下取出来,即只取到自己的请求信息而非其他人的。
我们还知道request对象中存储了很多信息,如request.method存储请求方式、request.json存储json标准字符串等等。下面以request.method为例,分析如何得到请求方式信息。
导入request方式如下:
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模块
pip3 install gevent-websocket
代码示例:
manage.py代码:
from flask import Flask, request, render_template
from geventwebsocket.handler import WebSocketHandler
from geventwebsocket.websocket import WebSocket # 提示用
from gevent.pywsgi import WSGIServer
import json app = Flask(__name__) user_socket_dict = {} # 用户字典 @app.route('/ws/<username>')
def ws(username):
print(request.environ) # 有个wsgi.websocket,通过它可以发消息
user_socket = request.environ.get('wsgi.websocket') #type:WebSocket
if user_socket:
user_socket_dict[username] = user_socket
print(user_socket_dict)
while 1:
msg = user_socket.receive()
msg_dict = json.loads(msg)
msg_dict['from_user'] = username
to_user = msg_dict.get('to_user')
# chat = msg_dict.get('msg')
u_socket = user_socket_dict.get(to_user) #type:WebSocket
u_socket.send(json.dumps(msg_dict)) @app.route('/')
def index():
return render_template('ws.html') if __name__ == '__main__':
http_serv = WSGIServer(('0.0.0.0',9527), app, handler_class=WebSocketHandler)
http_serv.server_forever()
ws.html代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body> <input id="username"type="text"><button onclick="login()">登录聊天室</button> 给<input id="to_user"type="text"> <input id="msg"type="text"><button onclick="send_msg()">发送</button> <div id="chat_list"style="width:500px; height:500px; border:1px solid red;"></div> </body> <script type="text/javascript"> var ws = null; // 因其他函数也可能会用到ws,所以不能放在某一个函数中 function login() {
var username = document.getElementById('username').value;
var ws = new WebSocket('ws://192.168.13.172:9527/ws'+username); // ws请求协议
ws.onmessage = function (data) {
console.log(data.data);
var recv_msg = JSON.parse(data.data);
var ptag = document.createElement('p');
ptag.innerText = recv_msg.from_user + ':' + recv_msg.msg;
document.getElementById('caht_list').appendChild(ptag)
};
} function send_msg() {
var to_user = document.getElementById('to_user').value;
var msg = document.getElementById('msg').value;
var send_dict = {
'to_user':to_user,
'msg':msg
};
ws.send(JSON.stringify(send_dict));
} </script> </html>
flask的请求上下文源码解读的更多相关文章
- Flask(4)- flask请求上下文源码解读、http聊天室单聊/群聊(基于gevent-websocket)
一.flask请求上下文源码解读 通过上篇源码分析,我们知道了有请求发来的时候就执行了app(Flask的实例化对象)的__call__方法,而__call__方法返回了app的wsgi_app(en ...
- flask 请求上下文源码(转)
本篇阅读目录 一.flask请求上下文源码解读 二.http聊天室(单聊/群聊)- 基于gevent-websocket 回到顶部 转:https://www.cnblogs.com/li-li/p/ ...
- Flask系列10-- Flask请求上下文源码分析
总览 一.基础准备. 1. local类 对于一个类,实例化得到它的对象后,如果开启多个线程对它的属性进行操作,会发现数据时不安全的 import time from threading import ...
- Flask框架 (四)—— 请求上下文源码分析、g对象、第三方插件(flask_session、flask_script、wtforms)、信号
Flask框架 (四)—— 请求上下文源码分析.g对象.第三方插件(flask_session.flask_script.wtforms).信号 目录 请求上下文源码分析.g对象.第三方插件(flas ...
- Flask请求上下文源码讲解,简单的群聊单聊web
请求上下文流程图 群聊html代码 <!DOCTYPE html> <html lang="en"> <head> <meta chars ...
- Flask核心机制--上下文源码剖析
一.前言 了解过flask的python开发者想必都知道flask中核心机制莫过于上下文管理,当然学习flask如果不了解其中的处理流程,可能在很多问题上不能得到解决,当然我在写本篇文章之前也看到了很 ...
- flask请求上下文源码分析
一.什么是上下文 每一段程序都有很多外部变量,只有像add这种简单的函数才是没有外部变量的,一旦你的一段程序有了外部变量,这段程序就不完整了,不能独立运行,你为了使他们能运行,就要给所有的外部变量一个 ...
- Flask请求和应用上下文源码分析
flask的request和session设置方式比较新颖,如果没有这种方式,那么就只能通过参数的传递. flask是如何做的呢? 1:本地线程,保证即使是多个线程,自己的值也是互相隔离 1 im ...
- Flask源码解读--所有可扩展点
一.前言 flask中有很多可扩展点(笔者这样称呼),其中包含了信号和请求钩子,这些信号和钩子有什么用呢?其主要作用用于帮助我们进行程序的耦合性,当然还可以让我们自定义一些行为.话不多说,通过阅读源码 ...
随机推荐
- RecyclerView的滚动事件分析
列表的滚动一般分为两种: 手指按下 -> 手指拖拽列表移动 -> 手指停止拖拽 -> 抬起手指 手指按下 -> 手指快速拖拽后抬起手指 -> 列表继续滚动 -> 停 ...
- python pandas相关知识点(练习)
首先引入库文件,并进行数据读取 import pandas as pd import numpy as np data_Base=pd.read_csv("D:\\Exam_Test\\un ...
- php从数据库选取记录形成列表(首页调用)
<ul class="e1"> <?php $querySel = "select ID,Tit,Addtime from news where DSh ...
- HDU2830
一开始把题目意思理解错啦,做那好久没做出来.本题是一个dp问题:题目说列可以无限次对换,设矩阵为M[i][j],要找到面积大的矩形其实就是处理连续1的个数问题,用d[i][j](i表示行,j表示列)表 ...
- hdu3591The trouble of Xiaoqian 多重背包+全然背包
//给出Xiaoqian的钱币的价值和其身上有的每种钱的个数 //商家的每种钱的个数是无穷,xiaoqian一次最多付20000 //问如何付钱交易中钱币的个数最少 //Xiaoqian是多重背包 / ...
- win下配置java环境变量
系统变量→新建 JAVA_HOME 变量 . 变量值填写jdk的安装目录(本人是 E:\Java\jdk1.7.0) 系统变量→寻找 Path 变量→编辑 在变量值最后输入 %JAVA_HOME%\ ...
- struts2学习笔记之表单标签的详解:s:checkbox/radio/select/optiontransferselect/doubleselect/combobox
struts2中的表单标签都是以s标签的方式定义的,同时,struts2为所有标签都提供了一个模板,C:\Users\180172\Desktop\struts2-core-2.2.1.1.jar\t ...
- hql小经验
hql如果查了子对象的属性,那么hql不允许子对象为空!
- 利用php调用so库文件中的代码
某个功能被编译到so文件中,那么如何通过php来调用它?一个方法是写一个php模块(php extension),在php中调用该模块内的函数,再通过该模块来调用so中的函数.下面做一个简单的例子,使 ...
- hdu5386(暴力)
题意: 给出两个n*n的矩阵,一个作为初始矩阵.一个作为目标矩阵,给出m个操作,操作有两种,一种是"L,x,y".代表我们要把x这一行赋成y,还有一种是"H,x,y&qu ...