第2章 - 程序的基本结构

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服务器,也就是说剩下的代码不会再执行)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值