经过上篇源码分析,咱们知道了有请求发来的时候就执行了app(Flask的实例化对象)的__call__方法,而__call__方法返回了app的wsgi_app(environ, start_response)方法的执行结果,而wsgi_app方法中有这样一句话:ctx = self.request_context(environ),还分析除了ctx是RequestContext类的实例化对象,并且ctx中含有有本次请求的request对象和session对象。html
接下来咱们重点分析flask是如何作到把request对象当成全局变量,而又保证了数据安全,即请求信息互不影响的。java
一、flask请求上文源码解读web
上篇咱们分析到了如何获得RequestContext实例化对象ctx,接下来ctx对象执行push方法,以下:json
RequestContext类中的push方法源码以下:flask
_request_ctx_stack是LocalStack类的实例化对象:后端
LocalStack类中的__init__方法以下:安全
Local类的__init__方法以下:服务器
get_ident是Local类所在文件中导入的一个方法名,该方法执行后会获得线程或协程ID,以下:websocket
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对象存储到某个地方。
二、下文
咱们知道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协议特色:短链接,无状态保存;
轮询:先后端一秒交互屡次,压力极大,而且消耗带宽,资源浪费极其严重;
长轮询:即让服务器保存个人一个链接状态,用于快速传递消息,节省带宽,释放压力,数据实时性强;
长链接:服务端及客户端节省极大的资源,能保证数据实时性;
带宽:1Mbps = 128KB/s
二、http聊天室
准备工做:下载gevent-websocket模块
1
|
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>