WSGI学习系列WebOb
1. WSGI Server <-----> WSGI Middleware<-----> WSGI Application
1.1 WSGI Server
wsgi server可以理解为一个符合wsgi规范的web server,接收request请求,封装一系列环境变量,按照wsgi规范调用注册的wsgi app,最后将response返回给客户端。
1.2 WSGI Application
wsgi application就是一个普通的callable对象,当有请求到来时,wsgi server会调用这个wsgi application。
这个对象接收两个参数,通常为environ,start_response。
environ可以理解为环境变量,跟一次请求相关的所有信息都保存在了这个环境变量中,包括服务器信息,客户端信息,请求信息。
start_response是一个callback函数,wsgi application通过调用start_response,将response headers/status 返回给wsgi server。
此外这个wsgi application会return一个iterator对象 ,这个iterator就是response body。
1.3 WSGI Middleware
中间件是为了使应用程序拥有额外的行为而存在的。如果你不能随意决定是否将它放到程序的前面,它就不再是中间件了。而是程序的一部分。
比如:URL dispatch功能,权限判断。
from wsgiref.simple_server import make_server URL_PATTERNS= ( ('hi/','say_hi'), ('hello/','say_hello'), ) class Dispatcher(object): def _match(self,path): path = path.split('/')[1] for url,app in URL_PATTERNS: if path in url: return app def __call__(self,environ, start_response): path = environ.get('PATH_INFO','/') app = self._match(path) if app : app = globals()[app] return app(environ, start_response) else: start_response("404 NOT FOUND",[('Content-type', 'text/plain')]) return ["Page dose not exists!"] def say_hi(environ, start_response): start_response("200 OK",[('Content-type', 'text/html')]) return ["kenshin say hi to you!"] def say_hello(environ, start_response): start_response("200 OK",[('Content-type', 'text/html')]) return ["kenshin say hello to you!"] app = Dispatcher() httpd = make_server('', 8000, app) print "Serving on port 8000..." httpd.serve_forever()
2.WebOb
WebOb是一个用于对WSGI Request环境进行包装,以及用于创建WSGI Response的一个包。
WebOb把WSGI的几个参数、返回的方法都封装成了Reqeust、Response这两个对象,同时还提供了一个使用方便的Exception对象。
Related API Link: http://docs.webob.org/en/latest/reference.html
2.1 Request
from webob import Request req = Request.blank('/') def wsgi_app(environ, start_response): start_response('200 OK', [('Content-type', 'text/plain')]) return ['Hi!'] print req.call_application(wsgi_app)
2.2 Response
from webob import Response from pprint import pprint
res = Response(content_type='text/plain', charset=None) f = res.body_file f.write('hey') f.write('test') # pprint(res.status) # pprint(res.headerlist) # pprint(res.body)
2.3 Full Sample about Request and Response
from webob import Request from webob import Response from webob.dec import wsgify # @wsgify def my_app(environ, start_response): req = Request(environ) res = Response() res.content_type = 'text/plain' parts = [] for name, value in sorted(req.environ.items()): parts.append('%s: %r' % (name, value)) res.body = 'n'.join(parts) return res(environ, start_response) req = Request.blank('/') res = req.get_response(my_app) print res
2.4 Exception
下述总结了WebOb对于HTTP返回码的类定义。
Exception HTTPException HTTPOk * 200 - :class:`HTTPOk` * 201 - :class:`HTTPCreated` * 202 - :class:`HTTPAccepted` * 203 - :class:`HTTPNonAuthoritativeInformation` * 204 - :class:`HTTPNoContent` * 205 - :class:`HTTPResetContent` * 206 - :class:`HTTPPartialContent` HTTPRedirection * 300 - :class:`HTTPMultipleChoices` * 301 - :class:`HTTPMovedPermanently` * 302 - :class:`HTTPFound` * 303 - :class:`HTTPSeeOther` * 304 - :class:`HTTPNotModified` * 305 - :class:`HTTPUseProxy` * 307 - :class:`HTTPTemporaryRedirect` HTTPError HTTPClientError * 400 - :class:`HTTPBadRequest` * 401 - :class:`HTTPUnauthorized` * 402 - :class:`HTTPPaymentRequired` * 403 - :class:`HTTPForbidden` * 404 - :class:`HTTPNotFound` * 405 - :class:`HTTPMethodNotAllowed` * 406 - :class:`HTTPNotAcceptable` * 407 - :class:`HTTPProxyAuthenticationRequired` * 408 - :class:`HTTPRequestTimeout` * 409 - :class:`HTTPConflict` * 410 - :class:`HTTPGone` * 411 - :class:`HTTPLengthRequired` * 412 - :class:`HTTPPreconditionFailed` * 413 - :class:`HTTPRequestEntityTooLarge` * 414 - :class:`HTTPRequestURITooLong` * 415 - :class:`HTTPUnsupportedMediaType` * 416 - :class:`HTTPRequestRangeNotSatisfiable` * 417 - :class:`HTTPExpectationFailed` * 422 - :class:`HTTPUnprocessableEntity` * 423 - :class:`HTTPLocked` * 424 - :class:`HTTPFailedDependency` * 428 - :class:`HTTPPreconditionRequired` * 429 - :class:`HTTPTooManyRequests` * 431 - :class:`HTTPRequestHeaderFieldsTooLarge` * 451 - :class:`HTTPUnavailableForLegalReasons` HTTPServerError * 500 - :class:`HTTPInternalServerError` * 501 - :class:`HTTPNotImplemented` * 502 - :class:`HTTPBadGateway` * 503 - :class:`HTTPServiceUnavailable` * 504 - :class:`HTTPGatewayTimeout` * 505 - :class:`HTTPVersionNotSupported` * 511 - :class:`HTTPNetworkAuthenticationRequired`