资讯专栏INFORMATION COLUMN

flask route对协议作用及设计思路解答

89542767 / 369人阅读

  小编写这篇文章的一个主要目的,主要是给大家讲解一下flask route,讲解的内容是flask route协议的一些相关作用,还有具体的一些设计思路,具体的思路性问题,下面去给大家做一个详细解答。


  引言


  本文主要梳理了flask源码中route的设计思路。


  首先,从WSGI协议的角度介绍flask route的作用;


  其次,详细讲解如何借助werkzeug库的Map、Rule实现route;


  最后,梳理了一次完整的http请求中route的完整流程。


  flask route设计思路


  源码版本说明


  本文参考的是flask 0.5版本的代码。


  flask 0.1版本的代码非常短,只有600多行,但是这个版本缺少blueprint机制。


  因此,我参考的是0.5版本。


  flask route示例


  直接使用flask官方文档中的例子


  from flask import Flask
  app=Flask(__name__)
  app.route('/')
  def hello_world():
  return'Hello World!'
  app.route('/post/')
  def show_post(post_id):
  #show the post with the given id,the id is an integer
  return'Post%d'%post_id
  if __name__=='__main__':
  app.run()


  此例中,使用app.route装饰器,完成了以下两个url与处理函数的route:


  {
  '/':hello_world,
  '/post/':show_post
  }


  这样做的效果为:


  当http请求的url为'/'时,flask会调用hello_world函数;


  当http请求的url为'/post/<某整数值>'(例如/post/32)时,flask会调用show_post函数;


  flask route的作用


  从上面的示例中其实可以明白:flask route的作用就是建立url与处理函数的映射。


  WSGI协议将处理请求的组件按照功能及调用关系分成了三种:server,middleware,application。


  其中,server可以调用middleware和application,middleware可以调用application。


  符合WSGI的框架对于一次http请求的完整处理过程为:


  server读取解析请求,生成environ和start_response,然后调用middleware;


  middleware完成自己的处理部分后,可以继续调用下一个middleware或application,形成一个完整的请求链;


  application位于请求链的最后一级,其作用就是生成最终的响应。


  http服务器(比如,nginx)-->WSGI server(比如gunicorn,SimpleHttpServer)-->middleware-->
  middleware-->...-->application


  如果接触过Java Web开发的人可能会立刻发现,这与servlet中的middleware机制是完全一致的。


  特别重要的:


  在上一小节的示例中app=Flask(__name__)创建了一个middleware,


  而这个middleware的核心作用是进行请求转发(request dispatch)。


  上面这句话非常重要,请在心里重复一百遍。


  上面这句话非常重要,请在心里重复一百遍。


  上面这句话非常重要,请在心里重复一百遍。


  进行请求转发的前提就是能够建立url与处理函数之间的映射关系,即route功能。


  因此,在flask中,route是Flask类的一个装饰器。


  flask route的实现思路


  通过上一小节,我们知道以下两点:


  flask route是url与处理函数的映射关系;


  在http请求时,Flask这个middleware负责完成对url对应的处理函数的调用;


  那么,如果是我们自己来实现route,思路也很简单:


  建立一个类Flask,这个类是一个middleware,并且有一个字典型的成员变量url_map;


  url_map={url:function}


  当http请求时,进行request dispatch:根据url,从url_map中找到function,然后调用function;


  调用后续的middleware或application,并把function的结果传递下去。


  flask的实现思路也是这样的。


  class Flask(object):
  def __init__(self):
  self.url_map={}#此处定义保存url与处理函数的映射关系
  def __call__(self,environ,start_response):#根据WSGI协议,middleware必须是可调用对象
  self.dispatch_request()#Flask的核心功能request dispatch
  return application(environ,start_response)#最后调用下一级的application
  def route(self,rule):#Flask使用装饰器来完成url与处理函数的映射关系建立
  def decorator(f):#简单,侵入小,优雅
  self.url_map[rule]=f
  return f
  return decorator
  def dispath_request(self):
  url=get_url_from_environ()#解析environ获得url
  return self.url_map[url]()#从url_map中找到对应的处理函数,并调用


  至此,一个简单的Flaskmiddleware的骨架就完成了。


  上面的Flask类主要功能包括:


  符合WSGI协议的middleware:可被调用,并且可以调用application


  能够保存url与处理函数的映射信息


  能够根据url找到处理函数并调用(即,request dispatch)


  当然,在实际中,不可能这么简单,但是基本思路是一致的。


  werkzeug库中的Map与Rule在Flask中的应用


  需要指出,上面实现的最简单的Flask类还是有很多问题的。


  比如,HTTP请求中相同的url,不同的请求方法,比如GET,POST如果对应不同的处理函数,该如何处理?


  flask使用了werkzeug库中的Map和Rule来管理url与处理函数映射关系。


  首先需要简单了解一下Map和Rule的作用:


  在werkzeug中,Rule的主要作用是保存了一组url,endpoint,methods关系:


  每个(url,endpoint,methods)都有一个对应的Rule对象:


  其实现如下:


  class Rule(object):
  def __init__(self,url,endpoint,methods):
  self.rule=url
  self.endpoint=endpoint
  self.methods=methods


  这里需要解释一下endpoint:


  前面说过:url与其处理函数可以使用一个字典来实现:{url:function}


  flask在实现的时候,在中间加了一个中介endpoint,于是,url与处理函数的映射变成了这样:


  url-->endpoint-->function#一个url对应一个endpoint,一个endpoint对应一个function
  {url:endpoint}#保存url与endpoint之间的关系
  {endpoint:function}#保存endpoint与function之间的关系


  于是,刚才我们实现的简单的flask骨架中{url:function}的字典,就变成了{endpoint:function},而{url:endpoint}这个映射关系就需要借助Map和Rule这两个类来完成。


  可以发现:endpoint就是url和处理函数映射关系中的一个中介,所以,它可以是任何可以用作字典键的值,比如字符串。


  但是在实际使用中endpoint,一般endpoint均为字符串,并且默认情况下:


  如果是通过Flask.route装饰器建立的映射关系,那么endpoint就是处理函数的函数名;


  如果是通过blueprint建立的映射关系,那么endpoint是blueprint名.处理函数名;


  因为,每建立一个url-->endpoint-->function关系就会创建一个Rule对象,所以,会有很多Rule对象存在。


  Map的作用则是保存所有Rule对象。


  所以,一般情况下Map的用法如下:


  m=Map([
  Rule('/',endpoint='index'),
  Rule('/downloads/',endpoint='downloads/index'),
  Rule('/downloads/',endpoint='downloads/show')
  ])


  在flask的源码中


  class Flask(object):
  def __init__(self):
  self.url_map=Map()#url_map为保存所有Rule关系的容器Map
  self.view_functions={}#view_functions保存endpoint-->function


  成员变量url_map保存所有的(url,endpoint,method)关系


  成员变量view_functions保存所有的{endpoint,function}关系


  所以,对于一个url,只要能找到(url,endpoint,method),就能根据endpoint找到对应的function。


  route的完整流程


  首先,建立Flask对象:


 app=Flask(__name__)


  然后,建立url与function之间的映射关系:


  app.route('/')
  def hello_world():
  return'Hello World!'


  在装饰器route中,创建(url,endpoint,method)和{endpoint:function}两组映射关系:


  if endpoint is None:
  endpoint=view_func.__name__#默认使用响应函数名作为endpoint
  self.url_map.add(Rule(url,endpoint,method))#保存(url,endpoint,method)映射关系
  self.view_functions[endpoint]=view_func#保存{endpoint:function}映射关系


  这样,就完成了对url和响应函数的映射关系。


  下一步,调用WSGI server响应http请求,在文章开始的示例中使用:

  app.run()


  调用python标准库提供的WSGI server,在实际使用时,可能是gunicorn或uwsgi。


  不论server是什么,最终都会调用Flask.__call__函数。这个函数完成request dispatch的任务。


  对于request dispatch而言,首先根据请求,解析environ,得到url,然后调用Map.match函数,这个函数会最终找到预先保存的(url,endpoint,method)映射,然后返回(endpoint,url请求参数),由于得到了endpoint,然后,可以从Flask.view_functions中直接取到对应的响应函数,所以,可以直接进行函数调用


  self.view_functions[endpoint](url请求参数)


  至此,就完成了完整的route。


  总结


  flask的Flask类是WSGI的dispatch middleware;
  Flask的url_map保存所有的(url,endpoint,method)映射关系;
  Flask的view_functions保存所有的{endpoint:function}映射关系;
  dispath request就是根据url找到endpoint,再根据endpoint找到function,最后调用function的过程


  综上所述,这篇文章就给大家介绍到这里了,希望可以给大家带来帮助。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/128315.html

相关文章

  • flask route设计思路

    摘要:引言本文主要梳理了源码中的设计思路。协议将处理请求的组件按照功能及调用关系分成了三种。不论是什么,最终都会调用函数。 引言 本文主要梳理了flask源码中route的设计思路。首先,从WSGI协议的角度介绍flask route的作用;其次,详细讲解如何借助werkzeug库的Map、Rule实现route;最后,梳理了一次完整的http请求中route的完整流程。 flask rou...

    vvpale 评论0 收藏0
  • 怎么使用Flask实现接收与上传图片

    小编写这篇文章的主要目的,主要是来给大家做出一个比较详细解答,主要是给大家解答关于python中的一些知识,比如Flask实现接手与上传图片,下面就给大家详细解答下。  接下来给搭建讲解Flask如何接受图片文件,上面是复杂写法,下面是简单写法,二选一即可。  思路整理:接收图片->定义一个图片存放的位置->给图片重命名(为了唯一性)->保存操作-&...

    89542767 评论0 收藏0
  • 从零开始搭建论坛(一):Web服务器与Web框架

    摘要:服务器通过协议与客户端通信,因此也被称为服务器。本文标题为从零开始搭建论坛一服务器与框架本文链接为更多阅读自己动手开发网络服务器一自己动手开发网络服务器二自己动手开发网络服务器三服务器网关接口实现原理分析最佳实践指南应用浅谈框架编程简介 之前用 Django 做过一个小的站点,感觉Django太过笨重,于是就准备换一个比较轻量级的 Web 框架来玩玩。Web.py 作者已经挂掉,项目好...

    dantezhao 评论0 收藏0
  • [贰]Flask web开发:程序的基本结构

    摘要:本篇对应书本第二章程序的基本结构。初始化导入模块创建类的实例注对于开发者来说,传给应用程序构造函数的参数是比较容易弄混淆的。不同的请求方法发送到相同的上时,会使用不同的视图函数进行处理。 本系列笔记是我阅读Miguel Grinberg的《Flask Web Development》的笔记,标题与书本同步。希望通过记录技术笔记的方式促进自己对知识的理解。 本篇对应书本第二章:程序的基本...

    maxmin 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<