黑客编程程序员Python 运维

python WSGI那些事

2017-07-14  本文已影响45人  woshiwodejia

》你知道WSGI吗

其实,我也不是太清楚,但是我知道一丢丢。记得第一份实习,当时用的是tornado,我就想看看这个东东到底是啥玩意,可是,我看了很久很久,始终没看明白!(听说你英语不咋地啊。。。。)落下,不议论。


画了一个分割线,有那么一天,一个牛逼的同事解释了这个东东,茅塞顿开)))===》

》 你不可不知道的Socket

如果你写过socket,对于以下脚本应该非常熟悉,我们写了一个server,然后用一个client访问

   #coding:utf-8

    import socket



    s = socket.socket(
        socket.AF_INET, socket.SOCK_STREAM)
    #now connect to the web server on port 80
    # - the normal http port
    s.connect(("localhost", 8082))

    s.sendall('Hello, world')
    data = s.recv(1024)

    s.close()
    print 'Received', repr(data)

然后 ,你会问这和http有什么关系,好吧,如果这样的话,就只能说你和我一样是白的不能再白的小白了!
如果你在浏览器中访问:http://localhost:8082/, 神奇的事情发生了。自己去看http协议吧 & 。)

》 封装

如果我们这样些后端代码,估计python也快走向没落了。我们变得优雅一点,于是就有了,Django,flask,tornado等(我就用过这几个%)),我们先看一个分装好的类SocketServer下的TCPServer,源代码非常推荐大家看看!!!!
来个流程图

Httpserver.jpg

其实我已经没有什么好说的了,但是,我看到这里不知道如何做处理,如何写View。然后我就去看flask的源码,还不能解决,又去看werkzeug中的代码,然后就懂了。其实你看BaseHTTPRequestHandler的handle时就应该有点思路了。没错,就是在handle中加入处理逻辑。

》再来说说这个WSGI

先给个链接:http://www.nowamagic.net/academy/detail/1330310

核心是这段代码:
  def application(environ, start_response):
        start_response('200 OK', [('Content-Type', 'text/html')])
        return '<h1>Hello, web!</h1>'

其实我们熟悉的django等叫做WebApplication,这个environ是由一个叫做WebServer传给我们的,也是由他完成最后的socket处理。当然还有一个中间件,看装饰器就明白了。
这个environ中是封装好的request,包括路由,请求方法,请求头,body等,start_response会处理请求头,
好吧,语言无力,直接看代码, 非常清晰

 def handle_one_request(self):
    """Handle a single HTTP request."""
    self.raw_requestline = self.rfile.readline()
    if not self.raw_requestline:
        self.close_connection = 1
    elif self.parse_request():
        return self.run_wsgi()


def run_wsgi(self):
    if self.headers.get('Expect', '').lower().strip() == '100-continue':
        self.wfile.write(b'HTTP/1.1 100 Continue\r\n\r\n')

    self.environ = environ = self.make_environ()
    headers_set = []
    headers_sent = []

    def write(data):
        assert headers_set, 'write() before start_response'
        if not headers_sent:
            status, response_headers = headers_sent[:] = headers_set
            try:
                code, msg = status.split(None, 1)
            except ValueError:
                code, msg = status, ""
            self.send_response(int(code), msg)
            header_keys = set()
            for key, value in response_headers:
                self.send_header(key, value)
                key = key.lower()
                header_keys.add(key)
            if 'content-length' not in header_keys:
                self.close_connection = True
                self.send_header('Connection', 'close')
            if 'server' not in header_keys:
                self.send_header('Server', self.version_string())
            if 'date' not in header_keys:
                self.send_header('Date', self.date_time_string())
            self.end_headers()

        assert isinstance(data, bytes), 'applications must write bytes'
        self.wfile.write(data)
        self.wfile.flush()
            def start_response(status, response_headers, exc_info=None):
        if exc_info:
            try:
                if headers_sent:
                    reraise(*exc_info)
            finally:
                exc_info = None
        elif headers_set:
            raise AssertionError('Headers already set')
        headers_set[:] = [status, response_headers]
        return write

    def execute(app):
        application_iter = app(environ, start_response)
        try:
            for data in application_iter:
                write(data)
            if not headers_sent:
                write(b'')
        finally:
            if hasattr(application_iter, 'close'):
                application_iter.close()
            application_iter = None

    try:
        execute(self.server.app)
    except (socket.error, socket.timeout) as e:
        self.connection_dropped(e, environ)
    except Exception:
        if self.server.passthrough_errors:
            raise
        from werkzeug.debug.tbtools import get_current_traceback
        traceback = get_current_traceback(ignore_system_exceptions=True)
        try:
            # if we haven't yet sent the headers but they are set
            # we roll back to be able to set them again.
            if not headers_sent:
                del headers_set[:]
            execute(InternalServerError())
        except Exception:
            pass
        self.server.log('error', 'Error on request:\n%s',
                        traceback.plaintext)

》OVER

多看源码,这一部分结束,以后看看模板和ORM

上一篇 下一篇

猜你喜欢

热点阅读