BaseHTTPRequestHandler模块和WSGI相关

开发服务器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

你可能感兴趣的:(BaseHTTPRequestHandler模块和WSGI相关)