flask的請求上下文源碼解讀

   1、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對象。javascript

  接下來咱們重點分析flask是如何作到把request對象當成全局變量,而又保證了數據安全,即請求信息互不影響的。html

  一、flask請求上文源碼解讀  java

  上篇咱們分析到了如何獲得RequestContext實例化對象ctx,接下來ctx對象執行push方法,以下:web

    

  RequestContext類中的push方法源碼以下:json

    

  _request_ctx_stack是LocalStack類的實例化對象:flask

     

  LocalStack類中的__init__方法以下:後端

    

  Local類的__init__方法以下:安全

    

  get_ident是Local類所在文件中導入的一個方法名,該方法執行後會獲得線程或協程ID,以下:服務器

    

  LocalStack類中的top是一個屬性方法,源碼以下:websocket

    

  下一步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對象中的相關信息。

   2、http聊天室(單聊/羣聊)   

  一、準備知識  

  http協議特色:短鏈接,無狀態保存;

  輪詢:先後端一秒交互屢次,壓力極大,而且消耗帶寬,資源浪費極其嚴重;

  長輪詢:即讓服務器保存個人一個鏈接狀態,用於快速傳遞消息,節省帶寬,釋放壓力,數據實時性強;

  長鏈接:服務端及客戶端節省極大的資源,能保證數據實時性;

  帶寬:1Mbps  = 128KB/s

  二、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>
相關文章
相關標籤/搜索