Bottle 是一个快速,简单和轻量级的 WSGI 微型 Web 框架的 Python。它作为单个文件模块分发,除了 Python 标准库之外没有依赖关系。

选择源码分析的版本是 Release 于 2009 年 7 月 11 日的 0.4.10 (这是我能找到的最早的发布版本了)。

为什么要分析 Bottle 这个比较冷门的框架?

Bottle 从发布至今一直贯彻的微型 Web 框架的理念。
Bottle 一直坚持单文件发布,也就是只有一个 bottle.py 文件。
除了 Python 标准库之外没有依赖关系。
与 Flask、Django 都遵循 PEP-3333 的 WSGI 协议。
0.4.10 版本代码量小,加上大量注释也只有不到 1000 行的代码。

所以,抛开框架的高级功能,单单从一个 Web 框架怎么处理请求的角度来看,Bottle 是最佳的选择。

Flask 从第一版开始就是依赖于 werkzeug 实现,更多的实现细节需要从 werkzeug 中查找。

Django 是个重型框架,不适合整体代码阅读,各个组件看看就可以。

Tornado 是个异类,和 WSGI 没有什么关系。

在阅读之前最好从 Github 上下载一份 0.4.10 版本的 Bottle 的源码,边看边阅读本文。

阅读本文你需要有如下技能:

熟悉 Python 的语法
熟悉 HTTP 协议
至少使用过一种 WSGI 的框架
了解 CGI
看得懂中文
流程结构分析

代码虽然不多,但是毫无目的的看难免思绪混乱,会看的心烦意乱,甚至会有产生「写的这是什么鬼?」的想法。

一个 Web 框架最核心也是最基本的功能就是处理 请求 和 响应。

但是在这之前,需要先创建一个 Server,才能开始处理啊!

所以大体的流程如下:

怎么创建一个 WSGI 的 Server 。
怎么处理到来的请求。
怎么处理响应。
创建 WSGI Server

在 Bottle 中关于创建一个标准的 WSGI Server 涉及的类或者方法只有 3 个。

注意,这里只关心一个标准的 WSGI,和核心功能。包括注释、错误处理、参数处理,会统统删除。

从文档中可以看到 Bottle 是通过一个 run 方法启动的。

WSGIRefServer 继承自 ServerAdapter,并且覆盖了 run 方法。

这个 run 方法本身也是很简单,通过 Python 标准库中的 make_server 创建了一个 WSGI Server 然后跑了起来。

注意在 run 方法中的 WSGIHandler 和 WSGIRefServer.run 中的 handler 参数,这个就是如何处理一次请求和响应的关键所在。

在这之前,还需要先看看 Bottle 对 Request 和 Respouse 的定义。

Request 定义

Bottle 为每次请求都会把一些参数保存在当前的线程中,通过继承 threading.local 实现线程安全。

Request 是由一个方法和 8 个属性构成。

bind 方法除了初始化一些变量以外,还添加 environ 到本次请求当中,environ 是一个字典包含了 CGI 的环境变量,更多 environ 内容参考PEP-3333 中 environ Variables 部分。

这三个属性比较简单,只是从 _environ 中取出了CGI 的某个环境变量。

GET 属性把 query_string 解析成字典放入当前请求的变量中,所以在请求中获取 GET 方法的参数可以使用 requst.GET['xxxx'] 这样子的用法。

POST 属性从 wsgi.input 中获取内容(也就是表单提交的内容)放入当前请求的变量中,可以通过request.POST['xxxx'] 来获取数据。

从 GET 和 POST 这两属性的使用来看,包括 Flask 和 Django 都实现了类似的方法,这方法属性拥有一样的步骤就是获取数据,然后转换成标准的字典格式,实现上来看没什么复杂的,就是普通的字符串处理而已。

params 属性提供了一个便利访问数据的方法。

Bottle 的 COOKIES 管理比较简单,只是单纯的从 CGI 中获取请求的 Cookie,如果存在的话直接返回。

以上就是 Bottle 的请求定义的内容。

简单总结来看,Request 从 CGI 中获取数据并且做一些数据处理,然后绑定到变量上。

Response 定义

整体结构和 Resquest 大致一样。

bind 方法只是初始化了一些变量。其中比较有意思的是 HeaderDict。

这是一个扩展于 dict 的字典,转化成大小写无关的 Title key ,还可以以列表方式添加多个成员。这个 HeaderDict 有意思的地方有两个:

与大小无关的 Ttile key,也就是会吧 key 转成以大写头其他小写的 key
存储重复 kv 值时候 values 会以 list 形式存储。如果 values 是多层 list,会自动解析成一层数据。
重写 items 方法,以二元元组方式返回数据,包括多值数据。

Response 对 Cookie 的初始化,并且提供了设置的方法。

为 content_type 属性提供了 set 和 get 方法,针对的是 Header 中的 Content-Type。

添加路由和 handler

这部分由一个装饰器和三个方法组成。

compile_route:路由正则
add_route:添加路由

route:路由装饰器

路由装饰器,简化 add_route 的调用。

ROUTES_SIMPLE 和 ROUTES_REGEXP 是两个全局字典,用于存储路由相关数据(方法,参数,地址)。

简单路由放入 ROUTES_SIMPLE,以 method 为 key ,在 method 中再以路由地址为 key,处理函数 handler 为 value 存储。

复杂路由放入 ROUTES_REGEXP,以 method 为 key,以 route 和 handler 组成的元组列表存储。

处理请求和响应

根据 PEP-3333 文档需要为编写一个可调用对象(可以是函数,或者是具有 __call__ 方法的类)。

Bottle 中的 WSGIHandler 正是这么一个可调用对象。

为了和代码契合度高,分析已经注释在当中。

处理流程如下:

拿到线程独立的 request 和 response
bind environ 数据
根据 match_url 找到处理的 handler 和参数,执行 
处理 Bottle 错误
处理内部错误
如果是文件则发送文件,不是的话正常返回字符串
设置 Set-Cookie header
结束
结束
Bottle 0.4.10 版本的核心内容就差么多,其他都是一些错误处理之类的。

该版本的 Bottle 以简单的过程,描述出了一个基于 WSGI 的 Web 框架是怎么样处理请求和响应的过程,完全基于 Python 标准库实现。

原文发布时间为:2017-05-22 
本文作者:正小歪
本文来自云栖社区合作伙伴“Python中文社区”,了解相关信息可以关注“Python中文社区”微信公众号

Python微型Web框架Bottle源码分析相关推荐

  1. 视频教程-RPC服务框架(Dubbo)源码分析-Java

    RPC服务框架(Dubbo)源码分析 鲁班学院-子路老师曾就职于谷歌.天猫电商等多家互联网公司,历任java架构师.研发经理等职位,参与并主导千万级并发电商网站与后端供应链研发体系搭建,多次参与电商大 ...

  2. Apollo 2.0 框架及源码分析(一) | 软硬件框架

    原文地址:https://zhuanlan.zhihu.com/p/33059132 前言 如引言中介绍的,这篇软硬件框架多为现有消息的整合加一些个人的想法.关于 Apollo 介绍的文章已经有许多, ...

  3. python微型web框架flask介绍

    Flask是一个基于python的,微型web框架.之所以被称为微型是因为其核心非常简单,同时具有很强的扩展能力.它几乎不给使用者做任何技术决定. 安装flask时应该注意其必须的几个支持包比如Jin ...

  4. Spring框架—SpringBean源码分析

    原文作者:Javadoop 原文地址:Spring IOC 容器源码分析 在继续往下之前,我们需要先了解 BeanDefinition.我们说 BeanFactory 是 Bean 容器,那么 Bea ...

  5. skynet 框架snax源码分析----变量注入

    skynet为了简化服务的编写,推出了snax框架,源码里也有一个例子pingserver.这是snax原创文章的第一篇,所以先就分析snax框架里的interface.lua源码,它的实现应用了一个 ...

  6. 高性能网络I/O框架-netmap源码分析

    前几天听一个朋友提到这个netmap,看了它的介绍和设计,确实是个好东西.其设计思想与业界不谋而合--因为为了提高性能,几个性能瓶颈放在那里,解决方法自然也是类似的. netmap的出现,它既实现了一 ...

  7. 阿里开源一站式分布式事务框架seata源码分析(AT模式下TM与RM分析)

    序言: 对于阿里开源分布式事务框架seata的详细了解可以参考官网,这里不会详细介绍.本章只会介绍seata中AT模式的源码分析(对阿seata有一定了解或者成功完成过demo). seata中一个事 ...

  8. FATFS文件系统框架及源码分析

    FATFS是一个为小型嵌入式系统设计的通用FAT(File Allocation Table)文件系统模块.FatFs 的编写遵循ANSI C,并且完全与磁盘I/O层分开.因此,它独立(不依赖)于硬件 ...

  9. Java类集框架 —— HashMap源码分析

    HashMap是基于Map的键值对映射表,底层是通过数组.链表.红黑树(JDK1.8加入)来实现的. HashMap结构 HashMap中存储元素,是将key和value封装成了一个Node,先以一个 ...

最新文章

  1. 昇腾AI 软硬件全栈平台
  2. 破解自动机器学习的黑匣子
  3. docker简易实践
  4. 数学图形(2.7)sphere sine wave
  5. 图像处理直方图匹配-巴氏系数原理及实现
  6. LeetCode 892. 三维形体的表面积(数学)
  7. 固态硬盘新趋势?美光3D QLC闪存出货量猛增75%
  8. 应用程序分别从SSRS2005和SSRS2008获取报表列表的方法差异
  9. 12.04 安装svn
  10. IS-IS基础网络配置实例
  11. 视频抠像软件Imagineer Systems Mokey
  12. html下拉菜单栏代码
  13. 20个网上赚钱你要知道的网站!
  14. Java基础——【双色球案例】判断中奖情况
  15. 迅雷 极速版 1.0.35.366
  16. 【环境搭建】手把手教你安装Ubuntu16.04系统
  17. DC-DC与LDO的区别及原理
  18. R中时间序列分析-趋势分析Trend
  19. 2020-10-24 python命令行多行输入
  20. SQL之分配、收回权限

热门文章

  1. insertionSortList
  2. AOP动态代理的实现机制
  3. 【转载】wpf学习笔记1
  4. 为保障处理器平稳运行请“三知”cpu
  5. 通过JavaScript简单的操作DOM(一)
  6. C语言关键字、标识符和注释
  7. PowerBI从SCCM数据库中分析数据和KPI展现
  8. android——记录从android studio2.3升级到android studio3.0版本遇到的坑
  9. 你的斗地主能拿多少炸?
  10. Laravel 5.2--如何让表单提交错误,不清空?