WSGI詳細介紹

1、WSGI是什麼
 
==================================
 

WSGI:Web Server Gateway Interfacecss

WSGI :不是Server,不是python模塊,不是python框架,也不是用python編寫的軟件。 
WSGI:是一個python標準(協議),由 PEP 3333描述。
它用來規定Web Server如何與python應用程序通訊。
若是一個Python應用程序(或框架,如Django)符合WSGI標準,那麼它能夠在任何符合WSGI標準的Server上運行(好比Apache)。
它對Server端和Python應用程序端都作了規定。
 
==================================
 
對Server端的規定:
一、Server必須把http請求以python 字典的形式,做爲第一參數傳遞給python應用程序。這個字典是這樣的:

 

{
   'REQUESTMETHOD':'GET',                            # method
   'PATH_INFO':'/path/to/python/application',     #URL
   'QUERY_STRING':'name=bill&age=10',         #參數
   'HTTP_ACCEPT':'text/html',                        #頭域
   'HTTP_HOST':'www.mydomain.com',             #頭域
   'SERVER_PORT':'8080',                             #Server 端口號
   'REMOTE_ADDR':'192.168.101.2' ,       #客戶端IP地址
   .........
}
這個字典內容不少,不一一列舉,總之這個字典包含了http請求的全部信息,包括method、URL、參數、頭域等,還包含了一些環境信息,好比Server端口號,請求者的ip地址等等。
 
二、Server必須把用來設置http返回碼和http響應頭域的 回調函數做爲第二參數傳遞給python應用程序。此回調函數接受兩個參數,第一個參數是http返回碼,以字符串形式給出,如:'200 OK';第二個參數是http響應頭,以list形式給出,此list裏放的是一個一個的tuple,如: [ ('Content-tpye', 'text'), ('Content-Length', '230') ]
 
三、Server從應用程序的返回值獲得http響應的消息體。這個返回值必須是一個iterator,Server遍歷這個iterator,把裏面的全部東西依次返回給客戶端瀏覽器。
 
=======================================
 
對python應用程序端的規定:
一、應用程序必須是一個callable,這個callable接受上述兩個參數,做爲第一和第二參數;這個callable返回一個iterator,裏面存放消息體。
 
二、應用程序從Server傳來的第一個參數取請求相關的信息。好比Server傳來的第一參數叫environ,想取客戶端IP,能夠這樣:

client_ip = environ['REMOTE_ADDR']html

 
三、應用程序利用Server傳來的第二個參數爲http響應設置返回碼和響應頭。好比Server傳來的第二參數叫set_http,想設置響應碼和響應頭,能夠這樣:

set_http('200 OK', ('Content-tpye', 'text'), ('Content-Length', '230'])python

 
四、應用程序把響應消息體以返回值的形式交給Server,這個返回值必須是iterator。好比想返回一個打印Hello World的網頁,能夠這樣:

return [r'<html><body><h1>Hello World<h1></body></html>']web

注意:雖然字符串自己就是iterator,但上述例子仍是將一個字符組包括在了[ ]內部使其成爲一個list。這是由於,把字符串做爲iterator,Server將會遍歷整個字符串,即一個字符一個字符的給客戶端發響應,這樣影響性能。若是把整個字符串做爲list的一個元素,則Server遍歷這個list時,把整個字符串一次性返回給客戶端,效率高。sql

 

===========================================數據庫

 

2、怎麼用WSGIdjango

咱們須要作什麼:小程序

一、咱們寫的python應用程序要遵照WSGI對應用程序的規定:即,咱們的應用程序是一個callable,接受兩個參數,返回一個iterator,如上所述。瀏覽器

二、咱們寫完符合WSGI規定的應用程序後,把程序安裝到符合WSGI規定的服務器上。所謂安裝,就是把某個URL跟咱們寫的某某個python程序對應起來。服務器

 

咱們怎麼作:

一、寫一個符合WSGI規定的應用程序,舉兩個例子。

例1:假如咱們想寫一個程序,讓訪問咱們網站的人看到 Hello WSIG !

那麼個人程序以下:

 

def application(env, set_http):

        set_http('200 OK', [('Content-type','text/html'),])

        return [r'<html><body><h1>Hello WSGI !</h1></body></html>']

例2:假如咱們想寫一個程序,讓訪問咱們網站的人看到本身的IP地址

那麼咱們的程序以下:

 

def application(env, set_http):

        ip = env['REMOTE_ADDR']

        set_http('200 OK', [('Content-type','text/html'),])

        return [r'<html><body><p>Your IP is : %s</p></body></html>'%ip]

以上兩個程序都是符合WSGI規定的。

 

二、把程序安裝到Server上。這裏咱們以Apache爲例,把以上兩個例子安裝到Apache上。

安裝以前要作個說明:Apache經過mod_wsgi來實現WSGI協議,mod_wsgi要求應用程序的callable必須叫 application,若是叫別的名字須要額外配置。這不是WSGI的規定,這是Apache mod_wsgi的規定。

 

2-一、首先安裝mod_wsgi,若是是Apache 2.4 以上的版本,這個mod是默認安裝完了的,若是是2.0 或者2.2 版本,須要手動安裝。用 yum -y install mod_wsgi 便可安裝成功。httpd 2.2 版本安裝mod_wsgi的過程當中須要注意的是,須要安裝httpd-devel 和 python-devel才行,能聯網的狀況下用yum安裝便可,另外python版本要高於2.3

 

2-二、把 Hell WSGI 這個程序安裝在 URL /hello 下,只須要在Apache的主配置文件httpd.conf中加入一行:

WSGIScriptAlias /hello /var/www/wsgi-app/hello.py

而後把hello.py扔到/var/www/wsgi-app 目錄下就能夠了。重啓httpd,訪問 xx.xx.xx.xx/hello 看到了Hello WSGI !

 

2-三、把顯示ip地址的程序安裝到 URL /ip 下,跟2-2同樣,就不寫了。

 

===================================

 

3、咱們不要這麼作

若是真像上面那樣,每寫一個程序都安裝一下,太麻煩,咱們不這麼作。

咱們用框架開發web應用程序,只要該框架符合WSGI協議。Django是一個符合WSGI的框架。

咱們把Django開發好的一個工程安裝到 「 / 」 下,其餘的URL交由Django處理,只安裝一次便可。

 

下面以Django Tutorial 中的 poll 程序 爲例,說一下怎麼把一個Django工程安裝到Apache上。

咱們在Apache的根目錄(/var/www/)下建立mysite目錄,把工程文件都拷貝進去。目錄結構以下:

 

而後咱們在httpd.conf中加入這2行:

 

WSGIScriptAlias / /var/www/mysite/mysite/wsgi.py

WSGIPythonPath /var/www/mysite

注意1,wsgi.py是咱們在建立工程時(django-admin.py startproject)自動生成的

注意2,跟安裝本身寫的小程序不一樣,此處要加入2行。第2行是告訴mod_wsgi,你的工程文件夾是能夠import的

 

在瀏覽器裏輸入  xx.xx.xx.xx/polls 驗證基本功能可用
 
在瀏覽器裏輸入 xx.xx.xx.xx/admin 發現admin頁面打不開,提示:attempt to write a readonly database,把sqlite文件的權限改成777以後,又提示 unable to open database file。在網上找了很久才找打答案:
sqlite 在開始一個事務的時候,須要在數據庫文件相同目錄下新建一個臨時文件,因此,數據庫文件所在的路徑必須對操做數據庫的用戶有寫權限!把數據庫文件以及其所在文件夾的權限都改成 777 後,問題解決。
最後的權限是這樣:
/var/www   755
/var/www/mysite 777
/var/www/mysite/sqlite3.db 777
 
當admin的頁面打開後,咱們發現樣子變了,全部的圖標,css都沒有,樣子很醜。
緣由是,當年咱們開發polls時,使用的是 manage.py runserver ,這個Django的development server。它會自動的爲每一個installed app 提供靜態文件服務。而diango自己不是不爲靜態文件提供服務的,因此admin的各類靜態文件都沒法傳到客戶端瀏覽器。
 
 
關於靜態文件的問題,咱們專門寫一篇來討論,這裏先不細講,本篇只關注WSGI。
 
==================  2015.04.16 更新 ===================================
1、
Server傳給應用程序的字典裏,以 HTTP_ 開頭的都是請求頭域,好比 HTTP_ACCEPT_ENCODING,,HTTP_CONNECTION,HTTP_USER_AGENT 等等。
可是注意,CONTENT_TYPE 和 CONTENT_LENGTH 不是以 HTTP_ 開頭的。
即 Server 要把用戶的請求頭裏,除了CONTENT_TYPE 和 CONTENT_LENGTH  的,都加上 HTTP_ 前綴再交給 python 應用程序。
 
2、
Server 把用戶請求的消息體,也放到這個字典裏,傳給應用程序。對應字典裏的 key 是:wsgi.input,它的 value 是一個 file-like object。

 

{
   .........
   'wsgi.input':a-file-like-object ,       #請求消息體
}
除了 wsgi.input 還有幾個必須出如今字典裏的東西,好比 wsgi.errors, wsgi.multithread 等等,因爲不經常使用,這裏就不展開說了。
較經常使用的就是 wsgi.input ,咱們的應用程序能夠用 env['wsgi.input'].read() 來讀取請求消息體,以便後續處理。
相關文章
相關標籤/搜索