zoukankan      html  css  js  c++  java
  • flask源码走读

    Flask-Origin

    源码版本

    一直想好好理一下flask的实现,这个项目有Flask 0.1版本源码并加了注解,挺清晰明了的,我在其基础上完成了对Werkzeug的理解部分,大家如果想深入学习的话,可以参考werkzeug_flow.md.

    阅读前

    为了更容易理解Flask的实现原理,你需要对WSGI协议以及HTTP协议有一些了解,建议先简单浏览下面的基本知识:

    Flask内部实现大量依赖于Werkzeug,包括请求和响应对象,路由匹配,URL生成等等,你可以阅读Werkzeug的文档来深入了解这些内容的具体实现。另外,如果你对模板渲染部分的内容感兴趣,也可以考虑阅读Jinja2文档:

    werkzeug源码阅读,可以参考下面的函数打断点,再测试一个请求,理清过程。

    其实可以参考简化后web服务实现思路,socket建立后,监听recv到的请求信息(no_wsgi_dome.no_wsgi.Socket._handle)并解析,然后调用相应的app.route对应的view_func.整个过程可以大致分为两部分:
    1. app-> werkzeug-> http-> socket 启动端口监听,注册各种方法.
    2. socket recv到请求-> 初始化RequestHandlerClass-> 调用Flask.__call__, wsgi_app在请求上下文中执行预处理方法,视图方法,后响应方法等.
    

    flask启动流程,只追溯了app到http再到socket的启动,主流程就是BaseWSGIServer初始化调用了HTTPServer的初始化,进而初始化了BaseServer,在socketserver上启动了服务开始监听端口:

    flask.Flask.run -> werkzeug.serving.run_simple ->
    werkzeug.serving.run_simple.inner ->werkzeug.serving.make_server ->
    BaseWSGIServer->HTTPServer.__init__(self, get_sockaddr(host, int(port),self.address_family), handler) ->
    BaseServer.__init__(self, server_address, RequestHandlerClass) ->
    werkzeug.serving.run_simple.inner.srv.serve_forever() ->
    socketserver.BaseServer.serve_forever 建立socket服务开始监听,当ready也就是有recv到请求时开始 _handle_request_noblock
    

    flask处理请求流程,追溯了socket接受到请求后触发app处理请求的主流程:

    curl发出请求->socket接受到请求 ->
    SocketServer.BaseServer.serve_forever._handle_request_noblock ->
    SocketServer.BaseServer.process_request ->
    SocketServer.BaseServer.finish_request ->
    socketserver.BaseServer.__init__:self.RequestHandlerClass(request, client_address, self)  ->
    这里要找出RequestHandlerClass是如何初始化的,它的真身是什么 ->
    socketserver.TCPServer.__init__:BaseServer.__init__(self, server_address, RequestHandlerClass) ->
    http.server.HTTPServer(未重写__init__) ->
    werkzeug.serving.BaseWSGIServer:HTTPServer.__init__(self, get_sockaddr(host, int(port),self.address_family), handler) (此处handler就是WSGIRequestHandler) ->
    RequestHandlerClass的真身已经找到,就是WSGIRequestHandler 也就是说每次请求来了都初始化一个WSGIRequestHandler去处理 ->
    处理的入口应该是werkzeug.serving.WSGIRequestHandler.handle可是简单一看并没找到是如何开始处理请求的->
    往它的父类BaseHTTPRequestHandler中找也没有 ->
    再往上socketserver.StreamRequestHandler ->
    找到了SocketServer.BaseRequestHandler.__init__:try:self.handle() 关键点 ->
    开始调用子类WSGIRequestHandler中的handle方法 ->
    werkzeug.serving.WSGIRequestHandler (注意handler和handle_one_request,WSGIRequestHandler重载了BaseHTTPServer.BaseHTTPRequestHandler中的方法,BaseHTTPRequestHandler由重载了 SocketServer.BaseRequestHandler )->
    werkzeug.serving.WSGIRequestHandler.handle_one_request调用werkzeug.serving.WSGIRequestHandler.run_wsgi 开始处理请求 ->
    run_wsgi.execute(self.server.app)将请求交予app来处理 ->
    flask.Flask.__call__ -> 
    flask.Flask.wsgi_app 开始app内的流程,交由wsgi_app在请求上下文中执行预处理方法,视图方法,后响应方法等。
    

    可以看到实现过程中Server,Handler用到了继承并重载,层层包装了web服务

    BaseWSGIServer继承了HTTPServer重写了BaseServer.serve_forever(包了一层),
    HTTPServer继承了TCPServer重写了server_bind,
    TCPServer继承了BaseServer重写了server_bind,
    主要思路要理清socket接受接请求后如何用请求触发调用app,这里主要是SocketServer.BaseRequestHandler.__init__:try:self.handle() 这个__init__才是处理请求真正开始的地方.
    

    进一步

    1. web的最原始的实现见 no_wsgi_dome ,不使用werkzeug,不使用wsgi约束,只是用socket如何实现http服务.这个对理解wsgi对http以及socket的封装有很好的借鉴意义.
    2. 补充了本地上下文相关的本地线程、本地堆栈、本地代理,并写了个LocalProxy_dome.py 辅助理解flask中是如何使用LocalProxy的。
    3. 我通过打断点,理通了app的启动和接受请求到处理请求的过程,可以参考werkzeug_flow.md配合flask_dome.py并手动打断点尝试一下.
    4. 根据下面的提示,自己理一下吧.
      • Flask中的请求响应循环
      • 路由系统
      • 本地上下文
      • 请求与响应对象
      • session
      • 蓝本
      • 模板渲染

    最后,要是觉得不错的话,点个赞支持一下吧,相关源码都放到了 我的github.

  • 相关阅读:
    ZOJ 2158 Truck History
    Knight Moves (zoj 1091 poj2243)BFS
    poj 1270 Following Orders
    poj 2935 Basic Wall Maze (BFS)
    Holedox Moving (zoj 1361 poj 1324)bfs
    ZOJ 1083 Frame Stacking
    zoj 2193 Window Pains
    hdu1412{A} + {B}
    hdu2031进制转换
    openjudge最长单词
  • 原文地址:https://www.cnblogs.com/lgjbky/p/10669397.html
Copyright © 2011-2022 走看看