from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello World!' if __name__ == '__main__': app.run()
from flask import Flask app = Flask(__name__)
@app.route('/') def hello_world(): return 'Hello World!'
def route(self, rule, **options): def decorator(f): endpoint = options.pop('endpoint', None) self.add_url_rule(rule, endpoint, f, **options) return f return decorator
def add_url_rule(self, rule, endpoint=None, view_func=None, **options): if endpoint is None: endpoint = _endpoint_from_view_func(view_func) options['endpoint'] = endpoint methods = options.pop('methods', None) # if the methods are not given and the view_func object knows its # methods we can use that instead. If neither exists, we go with # a tuple of only ``GET`` as default. if methods is None: methods = getattr(view_func, 'methods', None) or ('GET',) if isinstance(methods, string_types): raise TypeError('Allowed methods have to be iterables of strings, ' 'for example: @app.route(..., methods=["POST"])') methods = set(item.upper() for item in methods) # Methods that should always be added required_methods = set(getattr(view_func, 'required_methods', ())) # starting with Flask 0.8 the view_func object can disable and # force-enable the automatic options handling. provide_automatic_options = getattr(view_func, 'provide_automatic_options', None) if provide_automatic_options is None: if 'OPTIONS' not in methods: provide_automatic_options = True required_methods.add('OPTIONS') else: provide_automatic_options = False # Add the required methods now. methods |= required_methods rule = self.url_rule_class(rule, methods=methods, **options) rule.provide_automatic_options = provide_automatic_options self.url_map.add(rule) if view_func is not None: old_func = self.view_functions.get(endpoint) if old_func is not None and old_func != view_func: raise AssertionError('View function mapping is overwriting an ' 'existing endpoint function: %s' % endpoint) self.view_functions[endpoint] = view_func
執行完以後,將url放入app.url_map中;將視圖函數放入app.view_functions中:shell
if __name__ == '__main__': app.run()
def run(self, host=None, port=None, debug=None, **options): from werkzeug.serving import run_simple if host is None: host = '127.0.0.1' if port is None: server_name = self.config['SERVER_NAME'] if server_name and ':' in server_name: port = int(server_name.rsplit(':', 1)[1]) else: port = 5000 if debug is not None: self.debug = bool(debug) options.setdefault('use_reloader', self.debug) options.setdefault('use_debugger', self.debug) try: run_simple(host, port, self, **options) finally: # reset the first request information if the development server # reset normally. This makes it possible to restart the server # without reloader and that stuff from an interactive shell. self._got_first_request = False
try以前的代碼都是配置host、port、debug等參數。try中調用wsgi工具包werkzeug中的runsimple函數,用來創建socket連接,監聽客戶端數據,並進行解析處理,而後經過路由匹配找到視圖函數,將數據交給視圖處理後,再進行打包發給客戶端。最後一行代碼是將app中的_got_first_request標誌置爲False。當第一次客戶端請求到來時置位True,用來觸發before_first_request裝飾器(第一次請求來在視圖函數前面執行的代碼)的運行。json
請求來的時候執行run_simple(host, port, self, **options)中的第三個參數,即self(),self就是app,所以執行Flask類中__call__方法。flask
Flask類中__call__方法:app
def __call__(self, environ, start_response): """Shortcut for :attr:`wsgi_app`.""" return self.wsgi_app(environ, start_response)
from werkzeug.wrappers import Response from werkzeug.serving import run_simple def run_server(environ, start_response): print("environ:",environ) print("type environ:",type(environ)) print("start_response:", start_response) print("type start_response:", type(start_response)) response = Response('hello') return response(environ, start_response) if __name__ == '__main__': run_simple('127.0.0.1', 8000, run_server)
environ的類型是:<class 'dict'>,即字典類型socket
environ的內容以下:ide
environ: { 'wsgi.version': (1, 0), 'wsgi.url_scheme': 'http', 'wsgi.input': < _io.BufferedReader name = 736 > , 'wsgi.errors': < _io.TextIOWrapper name = '<stderr>' mode = 'w' encoding = 'UTF-8' > , 'wsgi.multithread': False, 'wsgi.multiprocess': False, 'wsgi.run_once': False, 'werkzeug.server.shutdown': < function WSGIRequestHandler.make_environ. < locals > .shutdown_server at 0x0000000012E1B510 > , 'SERVER_SOFTWARE': 'Werkzeug/0.14.1', 'REQUEST_METHOD': 'POST', 'SCRIPT_NAME': '', 'PATH_INFO': '/', 'QUERY_STRING': '', 'REMOTE_ADDR': '127.0.0.1', 'REMOTE_PORT': 11556, 'SERVER_NAME': '127.0.0.1', 'SERVER_PORT': '8000', 'SERVER_PROTOCOL': 'HTTP/1.1', 'CONTENT_TYPE': 'application/json', 'HTTP_CACHE_CONTROL': 'no-cache', 'HTTP_POSTMAN_TOKEN': 'fc8d2fdf-23c6-4461-9177-9c3965f09932', 'HTTP_USER_AGENT': 'PostmanRuntime/7.3.0', 'HTTP_ACCEPT': '*/*', 'HTTP_HOST': '127.0.0.1:8000', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate', 'CONTENT_LENGTH': '0', 'HTTP_CONNECTION': 'keep-alive' }
start_response的類型是:<class 'function'>,即函數類型函數
start_response的內容:工具
start_response: <function WSGIRequestHandler.run_wsgi.<locals>.start_response at 0x0000000012E2C510>
def wsgi_app(self, environ, start_response): ctx = self.request_context(environ) ctx.push() error = None try: try: # 對請求進行處理 response = self.full_dispatch_request() except Exception as e: error = e # 處理異常 response = self.handle_exception(e) except: error = sys.exc_info()[1] raise # 將處理後的數據返回 return response(environ, start_response) finally: if self.should_ignore_error(error): error = None ctx.auto_pop(error)
def full_dispatch_request(self): """Dispatches the request and on top of that performs request pre and postprocessing as well as HTTP exception catching and error handling. .. versionadded:: 0.7 """ # 處理第一次請求前的裝飾器before_first_requst函數 self.try_trigger_before_first_request_functions() try: request_started.send(self) rv = self.preprocess_request() # 若是before_request函數們處理返回的值爲None,則進行正式處理 if rv is None: rv = self.dispatch_request() except Exception as e: rv = self.handle_user_exception(e) # 使用after_response裝飾器函數對視圖函數執行後的結果進行處理 return self.finalize_request(rv)
def try_trigger_before_first_request_functions(self): """Called before each request and will ensure that it triggers the :attr:`before_first_request_funcs` and only exactly once per application instance (which means process usually). :internal: """ if self._got_first_request: return with self._before_request_lock: if self._got_first_request: return # self.before_first_request_funcs = [],列表中存放函數 for func in self.before_first_request_funcs: func() self._got_first_request = True
def preprocess_request(self): """Called before the actual request dispatching and will call each :meth:`before_request` decorated function, passing no arguments. If any of these functions returns a value, it's handled as if it was the return value from the view and further request handling is stopped. This also triggers the :meth:`url_value_preprocessor` functions before the actual :meth:`before_request` functions are called. """ bp = _request_ctx_stack.top.request.blueprint funcs = self.url_value_preprocessors.get(None, ()) if bp is not None and bp in self.url_value_preprocessors: funcs = chain(funcs, self.url_value_preprocessors[bp]) for func in funcs: func(request.endpoint, request.view_args) # 獲取before_requesth裝飾器函數並處理 funcs = self.before_request_funcs.get(None, ()) if bp is not None and bp in self.before_request_funcs: funcs = chain(funcs, self.before_request_funcs[bp]) for func in funcs: rv = func() if rv is not None: return rv
def dispatch_request(self): """Does the request dispatching. Matches the URL and returns the return value of the view or error handler. This does not have to be a response object. In order to convert the return value to a proper response object, call :func:`make_response`. .. versionchanged:: 0.7 This no longer does the exception handling, this code was moved to the new :meth:`full_dispatch_request`. """ req = _request_ctx_stack.top.request if req.routing_exception is not None: self.raise_routing_exception(req) rule = req.url_rule # if we provide automatic options for this URL and the # request came with the OPTIONS method, reply automatically if getattr(rule, 'provide_automatic_options', False) \ and req.method == 'OPTIONS': return self.make_default_options_response() # otherwise dispatch to the handler for that endpoint # 根據rule.endpoint找到app.view_functions中對應的處理函數,而後將req.view_args傳入, # 進行視圖函數處理,最後將結果返回 return self.view_functions[rule.endpoint](**req.view_args)