开发服务器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
从最先的父类中,可以看出简单的处理流程,接受三个参数,从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类中
完成基本运行上下文,set_up
创建self.rfile,self.wfile类文件对象
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
-回到最开始的自定义类中
显然他的钩子是do_GET
此外 django的WSGIRequestHandler,用于开发服务器
线上服务器
WSGI理解
全称:web server Gateway Interface
其中web server是指服务器(apache,nginx),Gateway(网关),interface(接口)
中文:Python应用程序(或框架)和Web服务器之间的接口规范!
作用:wsgi是将web server参数python化,封装为request对象传递给$apllication$命名的函数并接受其传出的response参数,
其作用的过程如下:
Nginx,WSGI,Flask 之间的对话。
Nginx:Hey,WSGI,我刚收到了一个请求,我需要你作些准备,然后由Flask来处理这个请求。
WSGI:OK,Nginx。我会设置好环境变量,然后将这个请求传递给Flask处理。
Flask:Thanks WSGI!给我一些时间,我将会把请求的响应返回给你。
WSGI:Alright,那我等你。
Flask:Okay,我完成了,这里是请求的响应结果,请求把结果传递给Nginx。
WSGI:Good job!Nginx,这里是响应结果,已经按照要求给你传递回来了。
Nginx:Cool,我收到了,我把响应结果返回给客户端。大家合作愉快~
具体的application
def application(#接收两个参数
#字典对象,包含类似CGI的环境参数,从客户端接收过来的请求有server填充
environ,
#start_response是一个回调函数,由server提供.用来发送HTTP status和header给server
start_response):
#响应体
response_body = "The request method was %s" % environ['REQUEST_METHOD']
#状态码
status = "200 OK"
#响应头
response_headers = [('Content-Type':'text/plain'),
('Content-Length':str(len(response_body)))]
#发送给server
start_response(status, response_headers)
#把响应体返回给server
#注意:尽管response_body是一个iterable,但是要包装成list,否则server会单个字节的发送给client.
return [response_body]
来一段django中的WSGIHandler实际例子
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对象
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=''))))
# #把响应体返回给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)
# 返回内容
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