開(kāi)發(fā)服務(wù)器BaseHTTPRequestHandler模塊
正向代理百度的例子,感受一下
# -*- coding:utf-8 -*-
import BaseHTTPServer
import hashlib
import os
import urllib2
class CacheHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
m = hashlib.md5()
m.update(self.path)
cache_filename = m.hexdigest()
if os.path.exists(cache_filename):
print "Cache hit"
data = open(cache_filename).readlines()
else:
print "Cache miss"
data = urllib2.urlopen("http://www.baidu.com" + self.path).readlines()
open(cache_filename, 'wb').writelines(data)
self.send_response(200)
self.end_headers()
self.wfile.writelines(data)
def run():
server_address = ('0.0.0.0', 9000)
httpd = BaseHTTPServer.HTTPServer(server_address, CacheHandler)
httpd.serve_forever()
if __name__ == '__main__':
run()
- SocketService
從最先的父類中,可以看出簡(jiǎn)單的處理流程,接受三個(gè)參數(shù),從setup->handle->finish
class BaseRequestHandler:
def __init__(self, request, client_address, server):
self.request = request
self.client_address = client_address
self.server = server
self.setup()
try:
self.handle()
finally:
self.finish()
def setup(self):
pass
def handle(self):
pass
def finish(self):
pass
- StreamRequestHandler類中
完成基本運(yùn)行上下文,set_up
創(chuàng)建self.rfile,self.wfile類文件對(duì)象
self.request為socket._scoketobject
def setup(self):
self.connection = self.request
if self.timeout is not None:
self.connection.settimeout(self.timeout)
if self.disable_nagle_algorithm:
self.connection.setsockopt(socket.IPPROTO_TCP,
socket.TCP_NODELAY, True)
self.rfile = self.connection.makefile('rb', self.rbufsize)
self.wfile = self.connection.makefile('wb', self.wbufsize)
def finish(self):
if not self.wfile.closed:
try:
self.wfile.flush()
except socket.error:
# An final socket error may have occurred here, such as
# the local error ECONNABORTED.
pass
self.wfile.close()
self.rfile.close()
- BaseHTTPRequestHandler
self.parse_request()
處理暴露出鉤子
mname = 'do_' + self.command
-回到最開(kāi)始的自定義類中
顯然他的鉤子是do_GET
此外 django的WSGIRequestHandler,用于開(kāi)發(fā)服務(wù)器
線上服務(wù)器
WSGI理解
全稱:web server Gateway Interface
其中web server是指服務(wù)器(apache,nginx),Gateway(網(wǎng)關(guān)),interface(接口)
中文:Python應(yīng)用程序(或框架)和Web服務(wù)器之間的接口規(guī)范!
作用:wsgi是將web server參數(shù)python化,封裝為request對(duì)象傳遞給$apllication$命名的函數(shù)并接受其傳出的response參數(shù),
其作用的過(guò)程如下:
Nginx,WSGI,F(xiàn)lask 之間的對(duì)話。
Nginx:Hey,WSGI,我剛收到了一個(gè)請(qǐng)求,我需要你作些準(zhǔn)備,然后由Flask來(lái)處理這個(gè)請(qǐng)求。
WSGI:OK,Nginx。我會(huì)設(shè)置好環(huán)境變量,然后將這個(gè)請(qǐng)求傳遞給Flask處理。
Flask:Thanks WSGI!給我一些時(shí)間,我將會(huì)把請(qǐng)求的響應(yīng)返回給你。
WSGI:Alright,那我等你。
Flask:Okay,我完成了,這里是請(qǐng)求的響應(yīng)結(jié)果,請(qǐng)求把結(jié)果傳遞給Nginx。
WSGI:Good job!Nginx,這里是響應(yīng)結(jié)果,已經(jīng)按照要求給你傳遞回來(lái)了。
Nginx:Cool,我收到了,我把響應(yīng)結(jié)果返回給客戶端。大家合作愉快~
具體的application
def application(#接收兩個(gè)參數(shù)
#字典對(duì)象,包含類似CGI的環(huán)境參數(shù),從客戶端接收過(guò)來(lái)的請(qǐng)求有server填充
environ,
#start_response是一個(gè)回調(diào)函數(shù),由server提供.用來(lái)發(fā)送HTTP status和header給server
start_response):
#響應(yīng)體
response_body = "The request method was %s" % environ['REQUEST_METHOD']
#狀態(tài)碼
status = "200 OK"
#響應(yīng)頭
response_headers = [('Content-Type':'text/plain'),
('Content-Length':str(len(response_body)))]
#發(fā)送給server
start_response(status, response_headers)
#把響應(yīng)體返回給server
#注意:盡管response_body是一個(gè)iterable,但是要包裝成list,否則server會(huì)單個(gè)字節(jié)的發(fā)送給client.
return [response_body]
來(lái)一段django中的WSGIHandler實(shí)際例子
class WSGIHandler(base.BaseHandler):
initLock = Lock()
request_class = WSGIRequest
def __call__(self, environ, start_response):
# Set up middleware if needed. We couldn't do this earlier, because
# settings weren't available.
if self._request_middleware is None:
with self.initLock:
try:
# Check that middleware is still uninitialized.
if self._request_middleware is None:
# 加載中間件
self.load_middleware()
except:
# Unload whatever middleware we got
self._request_middleware = None
raise
set_script_prefix(get_script_name(environ))
signals.request_started.send(sender=self.__class__, environ=environ)
try:
# 形成request對(duì)象
request = self.request_class(environ)
except UnicodeDecodeError:
logger.warning('Bad Request (UnicodeDecodeError)',
exc_info=sys.exc_info(),
extra={
'status_code': 400,
}
)
response = http.HttpResponseBadRequest()
else:
response = self.get_response(request)
response._handler_class = self.__class__
status = '%s %s' % (response.status_code, response.reason_phrase)
response_headers = [(str(k), str(v)) for k, v in response.items()]
for c in response.cookies.values():
response_headers.append((str('Set-Cookie'), str(c.output(header=''))))
# #把響應(yīng)體返回給server
start_response(force_str(status), response_headers)
if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'):
response = environ['wsgi.file_wrapper'](response.file_to_stream)
# 返回內(nèi)容
return response
參考
https://www.zhihu.com/question/19998865
http://blog.csdn.net/lihao21/article/details/52304119
https://github.com/lzjun567/note/blob/master/note/python/wsgi.md
https://www.fullstackpython.com/wsgi-servers.html