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() 来读取请求消息体,以便后续处理。