国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

mvc框架打造筆記之wsgi協議的優缺點以及接口實現

2020-01-04 14:51:21
字體:
來源:轉載
供稿:網友

前言:

又是WSGI ,這是我曾經比較熟悉的協議,以前針對實現了wsgi server的unicorn和uwsgi都寫過源碼解析的文章。  其實他們的實現也很簡單,就是給flask、django這樣的application傳遞environ,start_response 。

mvc框架,wsgi協議

什么是WSGI協議,什么是WSGI Server,他們的區別是什么?

上線的架構圖很容易誤導別人,乍一看有nginx這樣的web服務器,又有gunicorn這樣的wsgi server。  我們先說明wsgi 跟 wsgi server的關系,wsgi是個協議,是web底層跟application解耦的協議。wsgi server是自己做web服務器借用wsgi協議來調用application。 我們需要明確一點,nginx是無法直接跟flask application做通信,需要借用wsgi server。flask本身也有個web服務器是werkzeug,so 才能啟動服務并監聽端口。記得以前uwsgi沒名氣的時候,我們都在使用apache + mode_wsgi模式,apache也無法直接跟tornado通信,是借用mod_wsgi把torando做成了unix socket服務,說白了也是啟動了一個服務,靠apache來轉發。

nginx、apache在這里只是啟動了proxy的作用,那為什么不直接把uwsgi和gunicorn給暴露出去,因為nginx的靜態文件處理能力極強。

mvc框架,wsgi協議

WSGI怎么工作的

wsgi主要是兩層,服務器方 和 應用程序 :

1  服務器方:從底層解析http解析,然后調用應用程序,給應用程序提供(環境信息)和(回調函數), 這個回調函數是用來將應用程序設置的http header和status等信息傳遞給服務器方.

2  應用程序:用來生成返回的header,body和status,以便返回給服務器方。

WSGI把來自socket的數據包解析為http格式,然后進而變化為environ變量,這environ變量里面有wsgi本身的信息(比如 host, post,進程模式等),還有client的header及body信息。start_respnse是一個函調函數,必須要附帶兩個參數,一個是status(http狀態),response_headers(響應的header頭信息)。

像flask、django、tornado都會暴露WSGI協議入口,我們只需要自己實現WSGI協議,wsgi server然后給flask傳遞environ,及start_response, 等到application返回值之后,我再socket send返回客戶端。

WSGI的優點、缺點是什么?

優點:

多樣的部署選擇和組件之間的高度解耦

由于上面提到的高度解耦特性,理論上,任何一個符合WSGI規范的App都可以部署在任何一個實現了WSGI規范的Server上,這給Python Web應用的部署帶來了極大的靈活性。

Flask自帶了一個基于Werkzeug的調試用服務器。根據Flask的文檔,在生產環境不應該使用內建的調試服務器,而應該采取以下方式之一進行部署:

GUNICORN

UWSGI

缺點:

沒有

我們在wsgi層可以做什么時尚的操作:

  1. 黑白名單規則防御.
  2. 可以通過重寫環境變量,根據目標URL,將請求消息路由到不同的應用對象。這意思就是說,實現一套類似nginx location proxy的規則,可以把阻塞高性能轉給tornado的app. 當然這是理想化的操作.
  3. 允許在一個進程中同時運行多個應用程序或應用框架.
  4. 負載均衡和遠程處理,通過在網絡上轉發請求和響應消息.

我們用python具體實現這個wsgi server及協議.

#xiaorui.cc import socketimport StringIOimport sys class WSGIServer(object):  address_family = socket.AF_INET socket_type = socket.SOCK_STREAM request_queue_size = 1  def __init__(self, server_address):  # 創建一個可用的socket  self.listen_socket = listen_socket = socket.socket(   self.address_family,   self.socket_type  )  #socket的工作模式  listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  # Bind  listen_socket.bind(server_address) #綁定地址  # Activate  listen_socket.listen(self.request_queue_size) #監聽文件描述符  # Get server host name and port  host, port = self.listen_socket.getsockname()[:2]  self.server_name = socket.getfqdn(host)  self.server_port = port  self.headers_set = []  def set_app(self, application):  self.application = application  def serve_forever(self): #啟動WSGI server服務,不停的監聽并獲取socket數據。  listen_socket = self.listen_socket  while True:    self.client_connection, client_address = listen_socket.accept()   self.handle_one_request() #處理新連接  def handle_one_request(self): #主要處理函數  self.request_data = request_data = self.client_connection.recv(1024)  print(''.join(   '< {line}/n'.format(line=line)   for line in request_data.splitlines()  ))   self.parse_request(request_data)  env = self.get_environ()   #給flask/tornado傳遞兩個參數,environ,start_response  result = self.application(env, self.start_response)   # Construct a response and send it back to the client  self.finish_response(result)  def parse_request(self, text): #處理socket的http協議  request_line = text.splitlines()[0]  request_line = request_line.rstrip('/r/n')  # Break down the request line into components  (self.request_method, # GET   self.path,   # /hello   self.request_version # HTTP/1.1   ) = request_line.split()  def get_environ(self): #獲取environ數據  env = {}  env['wsgi.version']  = (1, 0)  env['wsgi.url_scheme'] = 'http'  env['wsgi.input']  = StringIO.StringIO(self.request_data)  env['wsgi.errors']  = sys.stderr  env['wsgi.multithread'] = False  env['wsgi.multiprocess'] = False  env['wsgi.run_once']  = False  env['REQUEST_METHOD'] = self.request_method # GET  env['PATH_INFO']   = self.path    # /hello  env['SERVER_NAME']  = self.server_name  # localhost  env['SERVER_PORT']  = str(self.server_port) # 8888  return env  def start_response(self, status, response_headers, exc_info=None): #創建回調函數.  server_headers = [   ('Date', 'Tue, 31 Mar 2015 12:54:48 GMT'),   ('Server', 'WSGIServer 0.3'),  ]  self.headers_set = [status, response_headers + server_headers]  def finish_response(self, result): #把application返回給WSGI的數據返回給客戶端。  try:   status, response_headers = self.headers_set   response = 'HTTP/1.1 {status}/r/n'.format(status=status)   for header in response_headers:    response += '{0}: {1}/r/n'.format(*header)   response += '/r/n'   for data in result:    response += data   # Print formatted response data a la 'curl -v'   print(''.join(    '> {line}/n'.format(line=line)    for line in response.splitlines()   ))   self.client_connection.sendall(response)  finally:   self.client_connection.close() SERVER_ADDRESS = (HOST, PORT) = '', 8888 def make_server(server_address, application): server = WSGIServer(server_address) server.set_app(application) return server if __name__ == '__main__': if len(sys.argv) < 2:  sys.exit('Provide a WSGI application object as module:callable') app_path = sys.argv[1] module, application = app_path.split(':') module = __import__(module) #動態加載模塊 application = getattr(module, application) #使用自省的模式加載application的WSGI協議入口。 httpd = make_server(SERVER_ADDRESS, application) print('WSGIServer: Serving HTTP on port {port} .../n'.format(port=PORT)) httpd.serve_forever()

下面是flask application的實例, 我們會發現python的常見web框架都兼容了wsgi接口,沒有例外。

#xiaorui.ccfrom flask import Flaskfrom flask import Responseflask_app = Flask('flaskapp') @flask_app.route('/search')def hello_world(): return Response(  'xiaorui.cc Golang vs python !/n',  mimetype='text/plain' ) app = flask_app.wsgi_app

運行方式很簡單:

python webserver2.py flaskapp:app

這樣一個wsgi就構成了,下次我們會借用這wsgi框架擴展成prefork wsgi server,類似gunicorn那樣。   以前在wsgi做過一些application的分流,但涉及到高并發的場景下的分流,還是建議直接在nginx層面做。 現在nginx lua的編程能力越來越強,大家都在使用nginx lua做網關及入口的開發。

參考文章:

https://ruslanspivak.com/lsbaws-part2/

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。


注:相關教程知識閱讀請移步到python教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 夹江县| 瑞昌市| 石棉县| 农安县| 新绛县| 彰化县| 临泉县| 珠海市| 龙南县| 汶川县| 温泉县| 连江县| 廊坊市| 鱼台县| 泰州市| 双牌县| 靖西县| 吴川市| 哈密市| 广安市| 南宁市| 衡东县| 随州市| 临邑县| 绥化市| 东光县| 博罗县| 海安县| 余庆县| 寿阳县| 通山县| 淳化县| 新民市| 金寨县| 东山县| 自治县| 湛江市| 东城区| 承德县| 邵东县| 肃北|