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

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

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

本篇文章我們主要介紹WSGI協(xié)議,該協(xié)議用來(lái)描述Server與Framework之間的通信接口,我們?nèi)粘J褂玫腜ython WEB框架Django、Flask、web.py等都遵循了該協(xié)議。下面我們就來(lái)詳細(xì)了解一下該協(xié)議的實(shí)現(xiàn)吧!

01 簡(jiǎn)介

WSGI協(xié)議全稱(chēng)Web Server Gateway Interface(Web服務(wù)器網(wǎng)關(guān)接口)。這是Python中定義的一個(gè)網(wǎng)關(guān)協(xié)議,規(guī)定了Web Server如何跟應(yīng)用程序交互。該協(xié)議的主要目的就是在Python中所有Web Server程序或者網(wǎng)關(guān)程序,能夠通過(guò)統(tǒng)一的協(xié)議跟Web框架或者Web應(yīng)用進(jìn)行交互。如果沒(méi)有這個(gè)協(xié)議,那每個(gè)程序都要各自實(shí)現(xiàn)各自的交互接口,而不能夠互相兼容,重復(fù)造輪子。使用統(tǒng)一的協(xié)議,Web應(yīng)用框架只要實(shí)現(xiàn)WSGI協(xié)議規(guī)范就可以與外部進(jìn)行交互,不用針對(duì)某個(gè)Web Server獨(dú)立開(kāi)發(fā)交互邏輯。

02 Web Server實(shí)現(xiàn)

在了解WSGI協(xié)議之前,我們先通過(guò)socket實(shí)現(xiàn)一個(gè)Web服務(wù)器。通過(guò)監(jiān)聽(tīng)本地端口來(lái)接客戶端的web請(qǐng)求,然后進(jìn)行響應(yīng),具體如下:

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. # 設(shè)置web server響應(yīng)內(nèi)容  
10. html_content = '<html><h1>My Frist Web Page<h1></html>'  
11.   
12. # 設(shè)置響應(yīng)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.     請(qǐng)求操作 
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("請(qǐng)求內(nèi)容: ", request)  
32.     conn.send(_resp.encode())  
33.     conn.close()  
34.   
35.   
36. def web_server():  
37.     # socket.AF_INET用于服務(wù)器與服務(wù)器之間同行   
38.     # socket.SOCK_STREAM用于基于TCP流的通信  
39.     server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
40.       
41.     # 監(jiān)聽(tīng)本地8888端口  
42.     server.bind(('127.0.0.1', 8888))  
43.     server.listen()  
44.     print("web server已經(jīng)啟動(dòng)")  
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()  

下面我們啟動(dòng)server服務(wù)器,查看頁(yè)面能不能正常訪問(wèn),同時(shí)看看

一文秒懂Web框架基礎(chǔ)之WSGI協(xié)議

 


一文秒懂Web框架基礎(chǔ)之WSGI協(xié)議

 

上面代碼就是最基本的web服務(wù)模型了,通過(guò)socket與HTTP協(xié)議提供Web服務(wù),但上面的web服務(wù)是單線程的,只有前一個(gè)請(qǐng)求處理結(jié)束才處理第二個(gè)請(qǐng)求,我們?cè)撛煲幌律厦娴拇a,通過(guò)python threading模塊實(shí)現(xiàn)多線程的web服務(wù)器,具體操作如下:

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. # 設(shè)置web server響應(yīng)內(nèi)容  
13. html_content = '<html><h1>這是線程({})的頁(yè)面 <h1></html>'  
14.   
15. # 設(shè)置響應(yīng)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.     請(qǐng)求操作 
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("請(qǐng)求內(nèi)容: ", 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用于服務(wù)器與服務(wù)器之間同行  
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.     # 監(jiān)聽(tīng)本地8888端口  
50.     server.bind(('127.0.0.1', 8888))  
51.     server.listen()  
52.     print("web server已經(jīng)啟動(dòng)")  
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.             # 通過(guò)threading實(shí)現(xiàn)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()  

我們?cè)僭L問(wèn)該服務(wù),其返回如下:

一文秒懂Web框架基礎(chǔ)之WSGI協(xié)議

 

通過(guò)上述改造我們就實(shí)現(xiàn)了多線程的web服務(wù)器,了解了web服務(wù)的基本實(shí)現(xiàn),下面我們就來(lái)看看WSGI的具體實(shí)現(xiàn)。

03 WSGI Application實(shí)現(xiàn)

在了解了基本的web服務(wù)的實(shí)現(xiàn),我們看WSGI協(xié)議,WSGI協(xié)議分為兩部分,一部分是web server或者網(wǎng)關(guān)就是上面web server代碼一樣,它監(jiān)聽(tīng)在某個(gè)端口上接受外部的請(qǐng)求,另外一部分就是web應(yīng)用,web server將接受到的請(qǐng)求數(shù)據(jù)通過(guò)WSGI協(xié)議規(guī)定的方式把數(shù)據(jù)傳遞給web應(yīng)用,web應(yīng)用處理完數(shù)據(jù)后設(shè)置對(duì)應(yīng)的狀態(tài)碼與header然后返回,web server拿到返回?cái)?shù)據(jù)之后再進(jìn)行HTTP協(xié)議封裝然后返回給客戶端,下面我們看看WSGI協(xié)議通過(guò)代碼的具體實(shí)現(xiàn)

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.             # 輸出數(shù)據(jù)前, 先發(fā)送響應(yīng)頭  
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.                     # 已經(jīng)發(fā)送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.             # 沒(méi)有body數(shù)據(jù)則不發(fā)送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)  

現(xiàn)在我們運(yùn)行編寫(xiě)的WSGI應(yīng)用,具體如下:

一文秒懂Web框架基礎(chǔ)之WSGI協(xié)議

 

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

04 總結(jié)

至此我們WSGI協(xié)議就講完了,如有什么問(wèn)題歡迎在文章后面進(jìn)行留言,最后如果喜歡本篇文章不要忘了點(diǎn)贊、關(guān)注與轉(zhuǎn)發(fā)哦!

分享到:
標(biāo)簽:框架 Web
用戶無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定