2.1 - 2.4 启动第一个flask服务器
from flask import Flask
app = Flask(__name__)
#申请一个处理客户端请求的对象
@app.route('/')
#路由:添加url请求和python函数的映射关系,客户端请求的url('/')会相应的在这部分处理
def index():
#视图函数 ,返回值是响应,也就是客户端收到的内容
return '<h1>Hello World!</h1>'
@app.route('/user/<name>')
def user(name):
#这里笔记python语法, '%s', str
return '<h1>Hello,%s!</h1>' % name
if __name__ == '__main__':
#name == '__main__' ,只有在直接启动脚本才会执行,如果是父级调用,那么不会执行
app.run(debug=True)
#开启服务器
注册路由
路由route怎么理解呢?客户端发送过来的url请求 -> 路由转发找到相应的处理函数->处理
路由的实现相当于一个MAP的映射关系,如果匹配失败,则返回404
这是app.route内部源码,可以看到只是多了个修饰器,核心部分是add_url_rule,添加了一条映射规则
def route(self, rule, **options):
"""A decorator that is used to register a view function for a
given URL rule. This does the same thing as :meth:`add_url_rule`
but is intended for decorator usage.
"""
def decorator(f):
endpoint = options.pop('endpoint', None)
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
def hello():
return "hello, world!"
app.add_url_rule('/', 'hello', hello)
rule好理解,就是url的地址,在匹配中也称作规则,那么多了个endpoint,怎么理解它的存在呢?这里有篇不错的博文。实际上endpoint的值是传入的视图函数的名字,保存于变量option字典中。建立的规则就是rule : endpoint。我们再来看看add_url_rule 具体怎么做的。
def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
"""Connects a URL rule. Works exactly like the :meth:`route`
decorator. If a view_func is provided it will be registered with the
endpoint.
"""
methods = options.pop('methods', None)
rule = self.url_rule_class(rule, methods=methods, **options)
self.url_map.add(rule) #改变1
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 #改变2
利用rule和endpoint注册了一个映射实例,然后改变1。然后通过endpoint在self.view_functions.get(endpoint)中查询有无同一个endpoint 对应着不同的视图函数 ,如果有那么抛出错误。 最后改变2,在view_functions添加上一个 endpoint 和 视图函数的新映射。从这里我们可以看到,同一个 endpoint 不可以对应多个 func
路由调度视图函数
当客户端发送request,路由接收后,是做什么处理呢?
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`.
"""
req = _request_ctx_stack.top.request
if req.routing_exception is not None:
self.raise_routing_exception(req)
rule = req.url_rule
# dispatch to the handler for that endpoint
return self.view_functions[rule.endpoint](**req.view_args)
上面我们提到过,self.view_functions 保存了 视图函数 func ,那么这里也就很好理解了。
_request_ctx_stack.top.request 这句代码中,看得出来客户端的请求被包装成RequestContext 对象被放在一个栈结构中。具体的RequestContext 就不再讨论了,无非是把一些参数包装成类,实现url -> endpoint 的匹配功能。
总结一下:
整个 flask 的路由过程就结束了,总结一下大致的流程:
通过 @app.route 或者 app.add_url_rule 注册应用 url 对应的处理函数
每次请求过来的时候,会事先调用路由匹配的逻辑,把路由结果保存起来,得到endpoint
dispatch_request 根据保存的路由结果,调用对应的视图函数
2.5请求-响应循环
这里引入了上下文(Context)的概念。操作系统老师曾解释上下文,大概意思是储存于CPU寄存器上的变量。我们在flask中,上下文可以理解成环境,一个客户端请求发送过来,那么环境就发生了改变,具体来说一些变量就发生了改变,那么我们服务器就针对这些变量进行操作。这些变量是全局的,又是多线程时线程独立的。
curret_app 程序上下文: 用于启动程序的实例
g 程序上下文:接收请求的对象,每次处理请求可以访问g
request 请求上下文 :请求对象,封装了客户端发出的HTTP请求的内容
session 请求上下文: 类似于java的Map, 映射了字典,方便编程
2.5.4 响应
定义了四种响应
Html、response对象、redirect重定向、abort(抛出异常,控制权交给web服务器,也就是说剩下的代码不会再执行)