WSGI是Web Service Gateway Interface的缩写。以层的角度来看,WSGI所在层的位置低于CGI。但与CGI不同的是WSGI具有很强的伸缩性且能运行于多线程或多进程的环境下,这是因为WSGI只是一份标准并没有定义如何去实现。实际上WSGI并非CGI,因为其位于web应用程序与web服务器之间,而web服务器可以是CGI,mod_python(注:现通常使用mod_wsgi代替),FastCGI或者是一个定义了WSGI标准的web服务器就像python标准库提供的独立WSGI服务器称为wsgiref。
WSGI标准在PEP(注:Python Enhancement Proposal)333中定义并被许多框架实现,其中包括现广泛使用的django框架。
如果你不想去阅读具体的PEP333<http://www.python.org/dev/peps/pep-0333/>,下面是对WSGI简短的描述:
WSGI应用是一个可调用的python对象(函数或实现__call__方法的类),该函数或__call__方法带有两个参数:第一个参数是WSGI环境变量,第二个参数是一个函数(注:函数带三个参数,第一个参数是返回的HTTP状态码信息,第二个参数是返回的HTTP头信息,第三个参数用于错误处理)用于处理完成返回时调用。
WSGI应用使用上面提供的函数进行返回调用并将数据以可迭代的形式返回。
WSGI环境变量类似于CGI环境变量,由web服务器或中间件进行添加,以键值对的形式保存。
下面以python标准库提供的独立WSGI服务器wsgiref为例,展示WSGI的使用:
1. 展示服务器生成的environment环境变量
#!/usr/bin/env python # -*- coding:utf-8 -*- from wsgiref.simple_server import make_server def application(environ, start_response): response_body = ['%s: %s' % (key, value) for key, value in sorted(environ.items())] response_body = '\n'.join(response_body) status = "200 OK" response_headers = [('Context-Type', 'text/plain'), ('Context-Length', str(len(response_body)))] start_response(status, response_headers) return [response_body] httpd = make_server('localhost', 8051, application) httpd.handle_request()
#!/usr/bin/env python # -*- coding:utf-8 -*- from wsgiref.simple_server import make_server from cgi import parse_qs, escape html = """ <html> <body> <form method="get" action=""> <p> Age: <input type="text" name="age"> </p> <p> Hobbies: <input name="hobbies" type="checkbox" value="software"> Software <input name="hobbies" type="checkbox" value="tunning"> Auto Tunning </p> <p> <input type="submit" value="Submit"> </p> </form> <p> Age: %s<br> Hobbies: %s </p> </body> </html>""" def application(environ, start_response): # Returns a dictionary containing lists as values. d = parse_qs(environ['QUERY_STRING']) # In this idiom you must issue a list containing a default value. age = d.get('age', [''])[0] # Returns the first age value. hobbies = d.get('hobbies', []) # Returns a list of hobbies. # Always escape user input to avoid script injection age = escape(age) hobbies = [escape(hobby) for hobby in hobbies] response_body = html % (age or 'Empty', ', '.join(hobbies or ['No Hobbies'])) status = '200 OK' # Now content type is text/html response_headers = [('Content-Type', 'text/html'), ('Content-Length', str(len(response_body)))] start_response(status, response_headers) return [response_body] httpd = make_server('localhost', 8051, application) # Now it is serve_forever() in instead of handle_request(). # In Windows you can kill it in the Task Manager (python.exe). # In Linux a Ctrl-C will do it. httpd.serve_forever()
#!/usr/bin/env python # -*- coding:utf-8 -*- from wsgiref.simple_server import make_server from cgi import parse_qs, escape html = """ <html> <body> <form method="post" action=""> <p> Age: <input type="text" name="age"> </p> <p> Hobbies: <input name="hobbies" type="checkbox" value="software"> Software <input name="hobbies" type="checkbox" value="tunning"> Auto Tunning </p> <p> <input type="submit" value="Submit"> </p> </form> <p> Age: %s<br> Hobbies: %s </p> </body> </html>""" def application(environ, start_response): # the environment variable CONTENT_LENGTH may be empty or missing try: request_body_size = int(environ.get('CONTENT_LENGTH', 0)) except (ValueError): request_body_size = 0 request_body = environ['wsgi.input'].read(request_body_size) d = parse_qs(request_body) # In this idiom you must issue a list containing a default value. age = d.get('age', [''])[0] # Returns the first age value. hobbies = d.get('hobbies', []) # Returns a list of hobbies. # Always escape user input to avoid script injection age = escape(age) hobbies = [escape(hobby) for hobby in hobbies] response_body = html % (age or 'Empty', ', '.join(hobbies or ['No Hobbies'])) status = '200 OK' # Now content type is text/html response_headers = [('Content-Type', 'text/html'), ('Content-Length', str(len(response_body)))] start_response(status, response_headers) return [response_body] httpd = make_server('localhost', 8051, application) # Now it is serve_forever() in instead of handle_request(). # In Windows you can kill it in the Task Manager (python.exe). # In Linux a Ctrl-C will do it. httpd.serve_forever()
对于上述的三个例子,在命令行进行保存目录,运行:python 保存的文件名.py,然后即可通过浏览器输入:http://localhost:8051进行访问