Python核心编程笔记————Web 编程:CGI 和 WSGI(三)

WCGI

动机

. CGI的目的是为了动态的创建内容,但是这种方式无法扩展,CGI进程针对每个请求进行创建(就像是打开Python解释器),用完就抛弃,如果接受了上千个请求,创建大量的语言解释器进程很快就会导致服务器停机。有两种方法来解决这个问题:服务器集成和外部进程

服务器集成

. 也称服务器API。当前应用最广泛的服务器解决方案是Apache HTTP Web 服务器,这是一个开源的解决方案,通常称为 Apache,拥有一个服务器 API。
  这类解决方案将网关集成进服务器。换句话说不是将服务器切分成多个语言解释器来分别处理请求,而是生成函数调用,运行应用程序代码,在运行过程中进行响应。
  其缺点也有很多,如:含有bug的代码会影响服务器实现的执行效率、不同语言的实现无法完全兼容,应用程序必须是线程安全的等等。

外部进程

. 这种方案是让CGI应用在服务器外部运行,当有请求时,服务器将请求传递到外部进程中。外部进程的存在时间很长,不会再处理玩请求后就结束。使用外部进程最广为人知的方案是FastCGI,外部进程相比服务器集成是更优的选择。
  同时,为了降低开发者尤其是Web矿建开发者的负担,建立了Web服务器网类接口(Web Server Gateway Interface,WSGI)标准。

WSGI简介

. WSGI规范创建于2003年,用于处理日益增多的不同的Web框架、Web服务器,及其它调用方式。
  根据WSGI定义,其应用是可调用的对象,其参数固定为以下两个:一个是含有服务器环境变量的字典,另一个是可调用对象,该对象使用HTTP状态码和会返回给客户端的HTTP头来初始化响应。其必须返回一个可迭代对象用于组成响应负载。以下是一个简单的示例:

def simple_wsgi_app(environ, start_response):
	status = '200 OK'
	headers = [('Content-type', 'text/plain')]
	start_response(status, headers)
	return ['Hello world!']

. start_response()这个可调用对象必须在应用执行,生成最终会发送回客户端的响应。响应必须含有 HTTP 返回码(200、300 等),以及 HTTP 响应头。另外返回的内容必须是可迭代的,如列表、生成器等,他们生成实际的响应负载。
  start_response()还有一个可选的第三参数(exc_info),这个参数含有异常信息。应用刚开始使用正常的一对参数执行,当发生错误的时候,会再次调用start_response(),但会将新的状态码、http头和exc_info一起传入,替换原有的内容。如果第二次调用时没有提供exc_info,则会发生错误。

参考服务器

. Python在标准库中提供了简单的参考服务器:wsgiref.simple_server.WSGIServer
  可以用这个类直接构建一个服务器。wsgiref包还提供了一个方便的函数:make_server(),通过这个函数可部署一个用于简单访问的参考服务器,下面是示例:

from wsgiref.simple_server import make_server

def simple_wsgi_app(environ, start_response):
    status = '200 OK'
    headers = [('Content-type', 'text/plain')]
    start_response(status, headers)
    return [u'Hello world!'.encode('utf8')]			#这里不encode会报错


httpd = make_server('',8000,simple_wsgi_app)
print('started app serving on port 8000...')
httpd.serve_forever()

. 运行这个模块后,在浏览器访问http://localhost:8000可以看到纯文本形式的Hello world!。其实wsgiref 模块还有一个示例应用demo_app(),可以导入demo_app,并将make_server的第三个参数换成demo_app()看看有什么不同。

中间件机封装WSGI应用

. 在某些情况下,除了应用程序本身之外,还希望在应用程序执行之前或是执行之后添加一些处理程序,即中间件。其要么对来自客户的数据进行预处理,然后发送给应用,要么在应用将响应负载发送给用户之前,对结果数据进行一些最终的调整。
  下面的例子是为之前的simple_wsgi_app的返回结果打上时间戳,并且使用类封装的方式,使参数整合到一个元组变量中,减少代码量:

from wsgiref.simple_server import make_server
from time import ctime

def simple_wsgi_app(environ, start_response):
    status = '200 OK'
    headers = [('Content-type', 'text/plain')]
    start_response(status, headers)
    return ['Hello world!\n','nice']			#这里和之前不一样,没有先encode了


class Ts_ci_wrapp(object):
    def __init__(self,app):
        self.orig_app = app

    def __call__(self,*stuff):
        return (('[%s] %s' % (ctime(),x)).encode() for x in self.orig_app(*stuff))

httpd = make_server('',8000,Ts_ci_wrapp(simple_wsgi_app))
print('started app serving on port 8000...')
httpd.serve_forever()

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章