日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

本篇文章我們主要介紹WSGI協議,該協議用來描述Server與Framework之間的通信接口,我們日常使用的Python WEB框架Django、Flask、web.py等都遵循了該協議。下面我們就來詳細了解一下該協議的實現吧!

01 簡介

WSGI協議全稱Web Server Gateway Interface(Web服務器網關接口)。這是Python中定義的一個網關協議,規定了Web Server如何跟應用程序交互。該協議的主要目的就是在Python中所有Web Server程序或者網關程序,能夠通過統一的協議跟Web框架或者Web應用進行交互。如果沒有這個協議,那每個程序都要各自實現各自的交互接口,而不能夠互相兼容,重復造輪子。使用統一的協議,Web應用框架只要實現WSGI協議規范就可以與外部進行交互,不用針對某個Web Server獨立開發交互邏輯。

02 Web Server實現

在了解WSGI協議之前,我們先通過socket實現一個Web服務器。通過監聽本地端口來接客戶端的web請求,然后進行響應,具體如下:

1. #!/usr/bin/env/ python  
2. # -*- coding:utf-8 -*-  
3.   
4. import socket  
5.   
6. END_TAG_F = b'nn'  
7. END_TAG_S = b'nrn'  
8.   
9. # 設置web server響應內容  
10. html_content = '<html><h1>My Frist Web Page<h1></html>'  
11.   
12. # 設置響應headers  
13. resp_args = ['HTTP/1.0 200 OK', 'Date: Sun, 22 nov 2020 19:00:00 GMT',  
14.              'Content-Type: text/html;charset=utf-8',  
15.              'Content-Length: {}rn'.format(len(html_content)), html_content]  
16.   
17. _resp = "rn".join(resp_args)  
18.   
19.   
20. def connet_operate(conn, addr):  
21.     """ 
22.     請求操作 
23.     :param conn:  
24.     :param addr:  
25.     :return:  
26.     """  
27.     request = b''  
28.     while END_TAG_F not in request and END_TAG_S not in request:  
29.         request += conn.recv(1024)  
30.   
31.     print("請求內容: ", request)  
32.     conn.send(_resp.encode())  
33.     conn.close()  
34.   
35.   
36. def web_server():  
37.     # socket.AF_INET用于服務器與服務器之間同行   
38.     # socket.SOCK_STREAM用于基于TCP流的通信  
39.     server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
40.       
41.     # 監聽本地8888端口  
42.     server.bind(('127.0.0.1', 8888))  
43.     server.listen()  
44.     print("web server已經啟動")  
45.   
46.     try:  
47.         while True:  
48.             conn, address = server.accept()  
49.             connet_operate(conn, address)  
50.     except:  
51.         server.close()  
52.   
53.   
54. if __name__ == "__main__":  
55.     web_server()  

下面我們啟動server服務器,查看頁面能不能正常訪問,同時看看

一文秒懂Web框架基礎之WSGI協議

 


一文秒懂Web框架基礎之WSGI協議

 

上面代碼就是最基本的web服務模型了,通過socket與HTTP協議提供Web服務,但上面的web服務是單線程的,只有前一個請求處理結束才處理第二個請求,我們該造一下上面的代碼,通過python threading模塊實現多線程的web服務器,具體操作如下:

1. #!/usr/bin/env/ python  
2. # -*- coding:utf-8 -*-  
3.   
4. import traceback  
5. import socket  
6. import errno  
7. import threading  
8.   
9. END_TAG_F = b'nn'  
10. END_TAG_S = b'nrn'  
11.   
12. # 設置web server響應內容  
13. html_content = '<html><h1>這是線程({})的頁面 <h1></html>'  
14.   
15. # 設置響應headers  
16. resp_args = ['HTTP/1.0 200 OK', 'Date: Sun, 22 nov 2020 19:00:00 GMT',  
17.              'Content-Type: text/html;charset=utf-8',  
18.              'Content-Length: {}rn']  
19.   
20.   
21. def connet_operate(conn, addr):  
22.     """ 
23.     請求操作 
24.     :param conn: 
25.     :param addr: 
26.     :return: 
27.     """  
28.     request = b''  
29.     while END_TAG_F not in request and END_TAG_S not in request:  
30.         request += conn.recv(1024)  
31.   
32.     print("請求內容: ", request)  
33.     c = threading.current_thread()  
34.     _ = html_content.format(c.name)  
35.     resp_args.Append(_)  
36.     content_length = len(_.encode())  
37.     _resp = "rn".join(resp_args)  
38.   
39.     _resp = _resp.format(content_length)  
40.     conn.send(_resp.encode())  
41.     conn.close()  
42.   
43.   
44. def web_server():  
45.     # socket.AF_INET用于服務器與服務器之間同行  
46.     # socket.SOCK_STREAM用于基于TCP流的通信  
47.     server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
48.     server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  
49.     # 監聽本地8888端口  
50.     server.bind(('127.0.0.1', 8888))  
51.     server.listen()  
52.     print("web server已經啟動")  
53.   
54.     try:  
55.         n = 0  
56.         while True:  
57.             try:  
58.                 conn, address = server.accept()  
59.             except socket.error as e:  
60.                 if e.args[0] != errno.EAGAIN:  
61.                     raise Exception(e)  
62.                 continue  
63.   
64.             n += 1  
65.             # 通過threading實現web server多線程  
66.             t = threading.Thread(target=connet_operate, args=(conn, address), name='thread{}'.format(n))  
67.             t.start()  
68.     except Exception as e:  
69.         print(traceback.format_exc(e))  
70.         server.close()  
71.   
72. if __name__ == "__main__":  
73.     web_server()  

我們再訪問該服務,其返回如下:

一文秒懂Web框架基礎之WSGI協議

 

通過上述改造我們就實現了多線程的web服務器,了解了web服務的基本實現,下面我們就來看看WSGI的具體實現。

03 WSGI Application實現

在了解了基本的web服務的實現,我們看WSGI協議,WSGI協議分為兩部分,一部分是web server或者網關就是上面web server代碼一樣,它監聽在某個端口上接受外部的請求,另外一部分就是web應用,web server將接受到的請求數據通過WSGI協議規定的方式把數據傳遞給web應用,web應用處理完數據后設置對應的狀態碼與header然后返回,web server拿到返回數據之后再進行HTTP協議封裝然后返回給客戶端,下面我們看看WSGI協議通過代碼的具體實現

1. #!/usr/bin/env/ python  
2. # -*- coding:utf-8 -*-  
3.   
4. import os  
5. import sys  
6.   
7.   
8. def _app(environ, response):  
9.     status = "200 OK"  
10.     resp_hearders = [('Content-Type', 'text/html')]  
11.     response(status, resp_hearders)  
12.     return [b'<h1>simple wsgi app</h1>n']  
13.   
14. def _to_bytes(content):  
15.     return content.encode()  
16.   
17. def run_with_cgi(application):  
18.     environ = dict(os.environ.items())  
19.     environ['wsgi.input'] = sys.stdin.buffer  
20.     environ['wsgi.errors'] = sys.stderr  
21.     environ['wsgi.version'] = (1, 0)  
22.     environ['wsgi.multithread'] = False  
23.     environ['wsgi.multiprocess'] = True  
24.     environ['wsgi.run_once'] = True  
25.   
26.     if environ.get('HTTPS', 'off') in ('on', '1'):  
27.         environ['wsgi.url_scheme'] = 'https'  
28.     else:  
29.         environ['wsgi.url_scheme'] = 'http'  
30.   
31.     headers_set = []  
32.     headers_sent = []  
33.   
34.     def write(data):  
35.         out = sys.stdout.buffer  
36.   
37.         if not headers_set:  
38.             raise ValueError("write before response()")  
39.   
40.         elif not headers_sent:  
41.             # 輸出數據前, 先發送響應頭  
42.             status, response_headers = headers_sent[:] = headers_set  
43.             out.write(_to_bytes('Status: {}rn'.format(status)))  
44.             for header in response_headers:  
45.                 out.write(_to_bytes('{}: {}rn'.format(header, header)))  
46.             out.write(_to_bytes('rn'))  
47.   
48.         out.write(data)  
49.         out.flush()  
50.   
51.     def response(status, response_headers, error_info=None):  
52.         if error_info:  
53.             try:  
54.                 if headers_sent:  
55.                     # 已經發送header就拋出異常  
56.                     raise (error_info[0], error_info[1], error_info[2])  
57.   
58.             finally:  
59.                 error_info = None  
60.   
61.         elif headers_set:  
62.             raise ValueError("Headers already set")  
63.   
64.         headers_set[:] = [status, response_headers]  
65.         return write  
66.   
67.     result = application(environ, response)  
68.   
69.     try:  
70.         for data in result:  
71.             # 沒有body數據則不發送header  
72.             if data:  
73.                 write(data)  
74.         if not headers_sent:  
75.             write('')  
76.   
77.     finally:  
78.         if hasattr(result, 'close'):  
79.             result.clost()  
80.   
81. if __name__ == "__main__":  
82.     run_with_cgi(_app)  

現在我們運行編寫的WSGI應用,具體如下:

一文秒懂Web框架基礎之WSGI協議

 

通過執行該應用直接返回了狀態信息、Header及body內容。上述代碼就是Application在WSGI協議的實現。我們要實現Application只需要能夠接收一個環境變量以及一個回調函數即可,如上面代碼的“result = application(environ, response)”,在處理完請求通過回調函數respose來設置響應的狀態和header,最后再返回body。在完成Application之后可以通過一些Web Server來調用,如Gunicorn Web server,限于篇幅限制就不詳細講解了,剛興趣的朋友可以安裝Gunicorn然后進行調用。

04 總結

至此我們WSGI協議就講完了,如有什么問題歡迎在文章后面進行留言,最后如果喜歡本篇文章不要忘了點贊、關注與轉發哦!

分享到:
標簽:框架 Web
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定