werkzeug에서 서버 처리 요청의 실현

17750 단어
서버를 성공적으로 구축한 후, 다음은 요청을 기다리고 처리하는 것입니다. 요청은 루트를 통해 상응하는 보기 함수에 분배됩니다. 다음은 함수 호출 과정입니다.
-> self._handle_request_noblock()/usr/lib/python2.7/SocketServer.py(295)_handle_request_noblock()-> self.process_request(request, client_address)/usr/lib/python2.7/SocketServer.py(321)process_request()-> self.finish_request(request, client_address)/usr/lib/python2.7/SocketServer.py(334)finish_request()-> self.RequestHandlerClass(request, client_address, self)/usr/lib/python2.7/SocketServer.py(649)__init__()-> self.handle()/home/steinliber/flask-source-code/env/local/lib/python2.7/site-packages/werkzeug/serving.py(217)handle()-> rv = BaseHTTPRequestHandler.handle(self)/usr/lib/python2.7/BaseHTTPServer.py(340)handle()-> self.handle_one_request()/home/steinliber/flask-source-code/env/local/lib/python2.7/site-packages/werkzeug/serving.py(252)handle_one_request()-> return self.run_wsgi()/home/steinliber/flask-source-code/env/local/lib/python2.7/site-packages/werkzeug/serving.py(194)run_wsgi()-> execute(self.server.app)/home/steinliber/flask-source-code/env/local/lib/python2.7/site-packages/werkzeug/serving.py(184)execute()-> for data in application_iter:/home/steinliber/flask-source-code/env/local/lib/python2.7/site-packages/werkzeug/debug/__init__.py(199)debug_application()
 
먼저 방금 만들어진 HTTPServer에서 보낸 요청을 처리하고 요청한 내용,headers,method 등을 얻으며 HTTPBASEREquestHandler를 초기화하여 이 값을 모두 HTTPBASEREquestHandler의 속성으로 설정합니다.WSGIRequestHandler는 HTTPBASEREquestHandler를 계승한 것이기 때문에 그는 이러한 속성을 이용하여 APP가 실행되는 environ을 구축할 수 있다.HTTPServer에서 Handle 메서드가 호출되고 WSGIRequestHandler의 원본은 다음과 같습니다.
class WSGIRequestHandler(BaseHTTPRequestHandler, object):

    """A request handler that implements WSGI dispatching."""

    @property
    def server_version(self):
        return 'Werkzeug/' + werkzeug.__version__

    def make_environ(self):
        request_url = url_parse(self.path)

        def shutdown_server():
            self.server.shutdown_signal = True

        url_scheme = self.server.ssl_context is None and 'http' or 'https'
        path_info = url_unquote(request_url.path)

        environ = {
            'wsgi.version':         (1, 0),
            'wsgi.url_scheme':      url_scheme,
            'wsgi.input':           self.rfile,
            'wsgi.errors':          sys.stderr,
            'wsgi.multithread':     self.server.multithread,
            'wsgi.multiprocess':    self.server.multiprocess,
            'wsgi.run_once':        False,
            'werkzeug.server.shutdown': shutdown_server,
            'SERVER_SOFTWARE':      self.server_version,
            'REQUEST_METHOD':       self.command,
            'SCRIPT_NAME':          '',
            'PATH_INFO':            wsgi_encoding_dance(path_info),
            'QUERY_STRING':         wsgi_encoding_dance(request_url.query),
            'CONTENT_TYPE':         self.headers.get('Content-Type', ''),
            'CONTENT_LENGTH':       self.headers.get('Content-Length', ''),
            'REMOTE_ADDR':          self.client_address[0],
            'REMOTE_PORT':          self.client_address[1],
            'SERVER_NAME':          self.server.server_address[0],
            'SERVER_PORT':          str(self.server.server_address[1]),
            'SERVER_PROTOCOL':      self.request_version
        }

        for key, value in self.headers.items():
            key = 'HTTP_' + key.upper().replace('-', '_')
            if key not in ('HTTP_CONTENT_TYPE', 'HTTP_CONTENT_LENGTH'):
                environ[key] = value

        if request_url.netloc:
            environ['HTTP_HOST'] = request_url.netloc

        return environ

    def run_wsgi(self):
        if self.headers.get('Expect', '').lower().strip() == '100-continue':
            self.wfile.write(b'HTTP/1.1 100 Continue\r
\r
') 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:
%s
', traceback.plaintext) def handle(self): """Handles a request ignoring dropped connections.""" rv = None try: rv = BaseHTTPRequestHandler.handle(self) except (socket.error, socket.timeout) as e: self.connection_dropped(e) except Exception: if self.server.ssl_context is None or not is_ssl_error(): raise if self.server.shutdown_signal: self.initiate_shutdown() return rv def initiate_shutdown(self): """A horrible, horrible way to kill the server for Python 2.6 and later. It's the best we can do. """ # Windows does not provide SIGKILL, go with SIGTERM then. sig = getattr(signal, 'SIGKILL', signal.SIGTERM) # reloader active if os.environ.get('WERKZEUG_RUN_MAIN') == 'true': os.kill(os.getpid(), sig) # python 2.7 self.server._BaseServer__shutdown_request = True # python 2.6 self.server._BaseServer__serving = False def connection_dropped(self, error, environ=None): """Called if the connection was closed by the client. By default nothing happens. """ 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 send_response(self, code, message=None): """Send the response header and log the response code.""" self.log_request(code) if message is None: message = code in self.responses and self.responses[code][0] or '' if self.request_version != 'HTTP/0.9': hdr = "%s %d %s\r
" % (self.protocol_version, code, message) self.wfile.write(hdr.encode('ascii')) def version_string(self): return BaseHTTPRequestHandler.version_string(self).strip() def address_string(self): return self.environ['REMOTE_ADDR'] def log_request(self, code='-', size='-'): self.log('info', '"%s" %s %s', self.requestline, code, size) def log_error(self, *args): self.log('error', *args) def log_message(self, format, *args): self.log('info', format, *args) def log(self, type, message, *args): _log(type, '%s - - [%s] %s
' % (self.address_string(), self.log_date_time_string(), message % args))

그중의 핸들 방법은 BASEREquestHandler의 핸들 방법을 포장합니다. socket에 오류가 발생하거나 시간이 초과되면 링크를 계속 시도합니다. initiate_shutdown은 종료 신호를 받았을 때 서버를 강제로 닫습니다. 이 핸들 방법은 공식 문서에서 핸들을 되돌려줍니다_one_request 방법, HTTP 요청을 받고 run_u를 호출합니다.wsgi 방법으로 처리,runnu에서ssgi에서 이전에 클래스 속성으로 설정된 Request 환경 변수를 environ 사전에 저장합니다.이것은 WSGI의 규범입니다. 서버는 앱에 엔비론과 start_를 제공해야 합니다.response 두 개의 매개 변수,start_response 메서드는 status와 reponse_를 설정합니다.headers, 구체적으로 PEP333규범을 볼 수 있습니다.그리고 excute를 실행하려고 시도합니다. 만약에 socket이 발생하면.error 또는 socket.timeout 이외의 오류는 debug 모드에서 디버그 페이지로 되돌아옵니다.
다음 excute 함수에서 그는 APP를 호출하여 엔비론과 start_를 전달한다response 두 개의 매개 변수는 WSGI 규범에 따라 교체 가능한 대상을 얻어서 write를 호출해서 이 데이터를 써야 합니다.write 방법에서 그는 먼저 start_를 확정할 것이다response가 먼저 호출됩니다. 우선 headers를 보내지 않으면 headers_set의 status 및response_header가 보낸 다음에 얻은 데이터를 보내면 서버 측의 임무가 기본적으로 완성됩니다.

좋은 웹페이지 즐겨찾기