1. 瀏覽器請求動態(tài)頁面過程
2. WSGI
怎么在你剛建立的Web服務(wù)器上運行一個Django應(yīng)用
和Flask應(yīng)用
,如何不做任何改變而適應(yīng)不同的web架構(gòu)呢嚷闭?
在以前攒岛,選擇 Python web 架構(gòu)
會受制于可用的web服務(wù)器
,反之亦然胞锰。如果架構(gòu)和服務(wù)器可以協(xié)同工作灾锯,那就好了:
但有可能面對(或者曾有過)下面的問題,當要把一個服務(wù)器和一個架構(gòu)結(jié)合起來時嗅榕,卻發(fā)現(xiàn)他們不是被設(shè)計成協(xié)同工作的:
那么顺饮,怎么可以不修改服務(wù)器和架構(gòu)代碼而確鄙可以在多個架構(gòu)下運行web服務(wù)器呢?答案就是 Python Web Server Gateway Interface (或簡稱 WSGI领突,讀作“wizgy”)暖璧。
WSGI允許開發(fā)者將選擇web框架和web服務(wù)器分開【可以混合匹配web服務(wù)器和web框架澎办,選擇一個適合的配對。比如,可以在Gunicorn 或者 Nginx/uWSGI 或者 Waitress上運行 Django, Flask, 或 Pyramid金砍。真正的混合匹配局蚀,得益于WSGI同時支持服務(wù)器和架構(gòu):
web服務(wù)器必須具備WSGI接口,所有的現(xiàn)代Python Web框架都已具備WSGI接口恕稠,它讓你不對代碼作修改就能使服務(wù)器和特點的web框架協(xié)同工作琅绅。
WSGI由web服務(wù)器支持,而web框架允許你選擇適合自己的配對鹅巍,但它同樣對于服務(wù)器和框架開發(fā)者提供便利使他們可以專注于自己偏愛的領(lǐng)域和專長而不至于相互牽制千扶。其他語言也有類似接口:java有Servlet API,Ruby 有 Rack骆捧。
3.定義WSGI接口
WSGI接口定義非常簡單澎羞,它只要求Web開發(fā)者實現(xiàn)一個函數(shù),就可以響應(yīng)HTTP請求敛苇。我們來看一個最簡單的Web版本的“Hello World!”:
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return 'Hello World!'
上面的application()
函數(shù)就是符合WSGI標準的一個HTTP處理函數(shù)妆绞,它接收兩個參數(shù):
- environ:一個包含所有HTTP請求信息的dict對象;
- start_response:一個發(fā)送HTTP響應(yīng)的函數(shù)枫攀。
整個application()
函數(shù)本身沒有涉及到任何解析HTTP的部分括饶,也就是說,把底層web服務(wù)器解析部分和應(yīng)用程序邏輯部分進行了分離来涨,這樣開發(fā)者就可以專心做一個領(lǐng)域了
不過图焰,等等,這個application()
函數(shù)怎么調(diào)用扫夜?如果我們自己調(diào)用楞泼,兩個參數(shù)environ和start_response我們沒法提供驰徊,返回的str也沒法發(fā)給瀏覽器笤闯。
所以application()
函數(shù)必須由WSGI服務(wù)器來調(diào)用。有很多符合WSGI規(guī)范的服務(wù)器棍厂。而我們此時的web服務(wù)器項目的目的就是做一個既能解析靜態(tài)網(wǎng)頁還可以解析動態(tài)網(wǎng)頁的服務(wù)器
4. web服務(wù)器-----WSGI協(xié)議---->web框架 傳遞的字典
{
'HTTP_ACCEPT_LANGUAGE': 'zh-cn',
'wsgi.file_wrapper': <built-infunctionuwsgi_sendfile>,
'HTTP_UPGRADE_INSECURE_REQUESTS': '1',
'uwsgi.version': b'2.0.15',
'REMOTE_ADDR': '172.16.7.1',
'wsgi.errors': <_io.TextIOWrappername=2mode='w'encoding='UTF-8'>,
'wsgi.version': (1,0),
'REMOTE_PORT': '40432',
'REQUEST_URI': '/',
'SERVER_PORT': '8000',
'wsgi.multithread': False,
'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'HTTP_HOST': '172.16.7.152: 8000',
'wsgi.run_once': False,
'wsgi.input': <uwsgi._Inputobjectat0x7f7faecdc9c0>,
'SERVER_PROTOCOL': 'HTTP/1.1',
'REQUEST_METHOD': 'GET',
'HTTP_ACCEPT_ENCODING': 'gzip,deflate',
'HTTP_CONNECTION': 'keep-alive',
'uwsgi.node': b'ubuntu',
'HTTP_DNT': '1',
'UWSGI_ROUTER': 'http',
'SCRIPT_NAME': '',
'wsgi.multiprocess': False,
'QUERY_STRING': '',
'PATH_INFO': '/index.html',
'wsgi.url_scheme': 'http',
'HTTP_USER_AGENT': 'Mozilla/5.0(Macintosh;IntelMacOSX10_12_5)AppleWebKit/603.2.4(KHTML,likeGecko)Version/10.1.1Safari/603.2.4',
'SERVER_NAME': 'ubuntu'
}
應(yīng)用程序示例
import time
def application(environ, start_response):
status = '200 OK'
response_headers = [('Content-Type', 'text/html')]
start_response(status, response_headers)
return str(environ) + '==Hello world from a simple WSGI application!--->%s\n' % time.ctime()