框架,即framework,特指爲解決一個開放性問題而設計的具備必定約束性的支撐結構,使用框架能夠幫你快速開發特定的系統。html
瀏覽器與服務器之間發起HTTP請求:nginx
1.瀏覽器發送一個HTTP請求; 2.服務器收到請求,生成一個HTML文檔; 3.服務器把HTML文檔做爲HTTP響應的Body發送給瀏覽器; 4.瀏覽器收到HTTP響應,從HTTP Body取出HTML文檔並顯示。
對於全部的Web應用,本質上其實就是一個socket服務端,用戶的瀏覽器其實就是一個socket客戶端。web
import socket def handle_request(client): buf = client.recv(1024) client.send("HTTP/1.1 200 OK\r\n\r\n".encode("utf8")) client.send("<h1 style='color:red'>Hello, yuan</h1>".encode("utf8")) def main(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(('localhost',8001)) sock.listen(5) while True: connection, address = sock.accept() handle_request(connection) connection.close() if __name__ == '__main__': main()
接受HTTP請求、解析HTTP請求、發送HTTP響應都是底層的東西,若是要研究這些底層那得花上必定的時間。所以咱們不但願接觸到TCP鏈接、HTTP原始請求和響應格式,因此,須要一個統一的接口,讓咱們專心用Python編寫Web業務。
這個接口就是WSGI:Web Server Gateway Interface。flask
Python Web Server Gateway Interface,翻譯過來時Python web服務器網關接口,實際上就是一種協議,咱們的應用(Django,Flask)實現了WSGI,就能夠配合實現了WSGI(uWSGI,gunicorn)的服務器工做了。
如下是結構圖:瀏覽器
在這種結構裏,uWSGI做爲服務器,它用到了HTTP協議以及wsgi協議,flask應用做爲application,實現了wsgi協議。當有客戶端發來請求,uWSGI接受請求,調用flask app獲得相應,以後相應給客戶端。
這裏說一點,一般來講,Flask等web框架會本身附帶一個wsgi服務器(這就是flask應用能夠直接啓動的緣由),可是這只是在開發階段用到的,在生產環境是不夠用的,因此用到了uwsgi這個性能高的wsgi服務器。服務器
這種結構裏,uWSGI做爲中間件,它用到了uwsgi協議(與nginx通訊),wsgi協議(調用Flask app)。當有客戶端發來請求,nginx先作處理(靜態資源是nginx的強項),沒法處理的請求(uWSGI),最後的相應也是nginx回覆給客戶端的。 app
多了一層反向代理有什麼好處?負載均衡
提升web server性能(uWSGI處理靜態資源不如nginx;nginx會在收到一個完整的http請求後再轉發給wWSGI)
nginx能夠作負載均衡(前提是有多個服務器)
保護了實際的web服務器(客戶端是和nginx交互而不是uWSGI)
框架
from wsgiref.simple_server import make_server def application(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) return [b'<h1>Hello, web!</h1>'] httpd = make_server('', 8080, application) print('Serving HTTP on port 8080...') # 開始監聽HTTP請求: httpd.serve_forever()
瀏覽器效果:socket
注意:
①整個application()函數自己沒有涉及到任何解析HTTP的部分,也就是說,底層代碼不須要咱們本身編寫,咱們只負責在更高層次上考慮如何響應請求就能夠了。
②Python內置了一個WSGI服務器,這個模塊叫wsgiref
③application()函數就是符合WSGI標準的一個HTTP處理函數,它接收兩個參數:
//environ:一個包含全部HTTP請求信息的dict對象;
//start_response:一個發送HTTP響應的函數。
④在application()函數中,調用:
start_response('200 OK', [('Content-Type', 'text/html')])
就發送了HTTP響應的Header,注意Header只能發送一次,也就是隻能調用一次start_response()函數。
start_response()函數接收兩個參數,一個是HTTP響應碼,一個是一組list表示的HTTP Header,每一個Header用一個包含兩個str的tuple表示。
一般狀況下,都應該把Content-Type頭髮送給瀏覽器。其餘不少經常使用的HTTP Header也應該發送。
⑤最後,函數的返回值b'<h1>Hello, web!</h1>'將做爲HTTP響應的Body發送給瀏覽器。
調用自己的HTML響應給瀏覽器
from wsgiref.simple_server import make_server def application(environ, start_response): # start_response('200 OK', [('Content-Type', 'text/html')]) print(environ['PATH_INFO']) path = environ['PATH_INFO'] start_response('200 OK', [('Content-Type', 'text/html')]) f1 = open("index1.html", "rb") data1 = f1.read() f2 = open("index2.html", "rb") data2 = f2.read() if path == "/test1": return [data1] elif path == "/test2": return [data2] else: return ["<h1>404</h1>".encode('utf8')] return [b'<h1>Hello, web!</h1>'] httpd = make_server('', 8080, application) print('Serving HTTP on port 8080...') # 開始監聽HTTP請求: httpd.serve_forever()