1. WSGI Server <-----> WSGI Middleware<-----> WSGI Application html
1.1 WSGI Serverweb
wsgi server能夠理解爲一個符合wsgi規範的web server,接收request請求,封裝一系列環境變量,按照wsgi規範調用註冊的wsgi app,最後將response返回給客戶端。服務器
1.2 WSGI Applicationapp
wsgi application就是一個普通的callable對象,當有請求到來時,wsgi server會調用這個wsgi application。函數
這個對象接收兩個參數,一般爲environ,start_response。ui
environ能夠理解爲環境變量,跟一次請求相關的全部信息都保存在了這個環境變量中,包括服務器信息,客戶端信息,請求信息。url
start_response是一個callback函數,wsgi application經過調用start_response,將response headers/status 返回給wsgi server。spa
此外這個wsgi application會return一個iterator對象 ,這個iterator就是response body。code
1.3 WSGI Middlewareorm
中間件是爲了使應用程序擁有額外的行爲而存在的。若是你不能隨意決定是否將它放到程序的前面,它就再也不是中間件了。而是程序的一部分。
好比: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`