前言

Bottle是一个Python Web框架。整个框架只有一个文件,不到4k行的代码,没有Python标准库以外的依赖,却包含了路由、模板和插件等Web框架常用功能。通过阅读Bottle源码来了解什么是Web框架和Web框架是怎么工作是再合适不过了。由于Bottle是一个支持WSGI的框架,在阅读源码之前,我们先来了解什么是WSGI。

注意:文中使用的Bottle版本为0.12.13。

WSGI

一般的Web服务器只能处理静态页面。如果涉及到动态内容,服务器就需要与Java/Python/Ruby等服务器语言进行交互,将内容交给它们处理。由于大多数的Web服务器都是用C写,它们不能直接执行服务器语言,所以两者之间需要一座桥(在实际应用中,通常会在Web服务器和WSGI应用中间添加一个应用服务器来支持WSGI)。而在Python中,WSGI就是这么一座桥。WSGI的实现分两个部分,一是服务器,二是应用程序。下面来看一看它们各自是什么样子的,以及两者之间是如何协作的。

 class Server:

     def __init__(self, server_address):
self.server_address = server_address def set_app(self, application):
self.app = application def serve_forever(self):
while True:
# socket.accept()
if request_comein():
self.handle_request() def handle_request(self):
request_data = self.get_request()
self.parse_request(request_data)
environ = self.get_environ()
result = self.application(environ, self.start_response)
self.send_response(result) def start_response(self, status, headers, exc_info):
pass def get_environ(self):
pass def get_request(self):
pass def parse_request(self, text):
pass def send_response(self, message):
pass def make_server(host, port, app, server=Server):
server = server((host, port))
server.set_app(app)
return server def simple_app(environ, start_response):
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
start_response(status, response_headers)
return 'Hello World!' if __name__ == '__main__':
server = make_server('localhost', 8080, simple_app)
server.serve_forever()

限于篇幅,这个服务器模型省略了很多细节,如果你想要一个简单又能运行的WSGI服务器,可以参考这里Let's Build A Web Server.Part 2.

服务器在接收到请求后,对请求报文的信息进行解析,结果保存在一个名为environ的字典中。随后以environ与处理头信息的start_response函数作为参数,调用应用程序 application(environ, start_response) 。最后将应用的结果组成新的响应,发送回客户端。

在应用程序方面,WSGI应用是一个可调用的对象。它可以是一个函数,方法,类,或者是一个带有__call__方法的实例。上面的应用就是一个函数。

当各种服务器和应用程序/框架都按照WSGI的标准进行开发时,我们可以根据需求自由地组合不同的服务器和框架。

Bottle最简应用

在简单了解完WSGI后,我们回到Bottle,来观察一个Bottle应用是什么样子的,如何运行,跟我们的模型有什么区别。

 from bottle import Bottle, run

 app = Bottle()

 @app.route('/hello')
def hello():
return 'Hello World!' run(app, host='localhost', port=8080, server='wsgiref')

现在运行这个程序,用浏览器访问地址'localhost:8080/hello'就会看到'Hello World!'。

1. 与上面的应用不同,Bottle应用是一个实例。按照WSGI规定,Bottle对象要实现__call__方法:

 def __call__(self, environ, start_response):
''' Each instance of :class:'Bottle' is a WSGI application. '''
return self.wsgi(environ, start_response)

所以这个Bottle.wsgi方法就是服务器调用Bottle应用的入口,同时也是我们阅读源码的入口。

2. @app.route()这个装饰器将一个函数绑定到一个URL上。当我们访问'localhost:8080/hello'时,hello函数就会被调用。

3. Bottle默认的服务器是wsgiref(Python标准库里的一个WSGI简单实现)。当然Bottle还为许多服务器编写了适配器(Adapter),只需要改变server的值,run()函数会根据服务器的名字寻找相应的适配器。无需编写额外的代码。

run函数和适配器部分代码:

 def run(app=None, server='wsgiref', host='127.0.0.1', port=8080,
interval=1, reloader=False, quiet=False, plugins=None,
debug=None, **kargs):
if server in server_names:
server = server_names.get(server)
if isinstance(server, basestring):
server = load(server)
if isinstance(server, type):
server = server(host=host, port=port, **kargs)
if not isinstance(server, ServerAdapter):
raise ValueError("Unknown or unsupported server: %r" % server)
...
server.run(app) class MeinheldServer(ServerAdapter):
def run(self, handler):
from meinheld import server
server.listen((self.host, self.port))
server.run(handler)

最后

在本文中,我们简单介绍了在WSGI标准下服务器和应用如何进行交互。下一篇,我们继续围绕这个最简应用,讲讲与@app.route()有关的路由功能。

Bottle源码阅读笔记(一):WSGI的更多相关文章

  1. Bottle源码阅读笔记(二):路由

    前言 程序收到请求后,会根据URL来寻找相应的视图函数,随后由其生成页面发送回给客户端.其中,不同的URL对应着不同的视图函数,这就存在一个映射关系.而处理这个映射关系的功能就叫做路由.路由的实现分为 ...

  2. CI框架源码阅读笔记5 基准测试 BenchMark.php

    上一篇博客(CI框架源码阅读笔记4 引导文件CodeIgniter.php)中,我们已经看到:CI中核心流程的核心功能都是由不同的组件来完成的.这些组件类似于一个一个单独的模块,不同的模块完成不同的功 ...

  3. CI框架源码阅读笔记4 引导文件CodeIgniter.php

    到了这里,终于进入CI框架的核心了.既然是“引导”文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http://you.host.c ...

  4. CI框架源码阅读笔记3 全局函数Common.php

    从本篇开始,将深入CI框架的内部,一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说,全局函数具有最高的加载优先权,因此大多数的框架中BootStrap ...

  5. CI框架源码阅读笔记2 一切的入口 index.php

    上一节(CI框架源码阅读笔记1 - 环境准备.基本术语和框架流程)中,我们提到了CI框架的基本流程,这里再次贴出流程图,以备参考: 作为CI框架的入口文件,源码阅读,自然由此开始.在源码阅读的过程中, ...

  6. 源码阅读笔记 - 1 MSVC2015中的std::sort

    大约寒假开始的时候我就已经把std::sort的源码阅读完毕并理解其中的做法了,到了寒假结尾,姑且把它写出来 这是我的第一篇源码阅读笔记,以后会发更多的,包括算法和库实现,源码会按照我自己的代码风格格 ...

  7. Three.js源码阅读笔记-5

    Core::Ray 该类用来表示空间中的“射线”,主要用来进行碰撞检测. THREE.Ray = function ( origin, direction ) { this.origin = ( or ...

  8. PHP源码阅读笔记一(explode和implode函数分析)

    PHP源码阅读笔记一一.explode和implode函数array explode ( string separator, string string [, int limit] )此函数返回由字符 ...

  9. AQS源码阅读笔记(一)

    AQS源码阅读笔记 先看下这个类张非常重要的一个静态内部类Node.如下: static final class Node { //表示当前节点以共享模式等待锁 static final Node S ...

随机推荐

  1. Jquery对复选框CheckBox的操作

    checkbox: 多选框 //获取选中值  checkbox:$("#checkbox_id").attr("value"): 多选框checkbox,打勾: ...

  2. TaintDroid简介

    1.Information-Flow tracking,Realtime Privacy Monitoring.信息流动追踪,实时动态监控. 2.TaintDroid是一个全系统动态污点跟踪和分析系统 ...

  3. 【PAT_Basic日记】1004 成绩排名

    至今仍然存在问题,第一个测试点不过 #include <stdio.h> #include <stdlib.h> #include <string.h> typed ...

  4. 封装Web Uploader 上传插件、My97DatePicker、百度 编辑器 的使用 (ASP.NET MVC)

    Web Uploader: WebUploader是由Baidu WebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件.在现代的浏览器里面能充分发挥HTML5的优 ...

  5. 多个git账号的SSH配置

    一般使用git都只需要维持一个默认的git账户就可以打天下了. 但如果自己确实需要多个git账号的需求的话,就有必要配置多个ssh key了. 首先为生成多个ssh key ssh-keygen -t ...

  6. Java设置Excel单元格式

    XSSFWorkbook wb = new XSSFWorkbook(); CellStyle style = wb.createCellStyle(); style.setBorderRight(C ...

  7. callLater

    UIComponent的方法,该方法在每次更新屏幕之前,Flash Player 或 AIR 都会调用为更新预定的函数集.有时,应在下次更新时调用函数,以执行为当前更新预定的其余代码.部分功能(如效果 ...

  8. IOC容器的依赖注入

    1.依赖注入发生的时间 当Spring IoC容器完成了Bean定义资源的定位.载入和解析注册以后,IoC容器中已经管理类Bean定义的相关数据,但是此时IoC容器还没有对所管理的Bean进行依赖注入 ...

  9. 用PetaPoco为ASP.NET已有数据库建模

    序:最近一直在抓紧重构公司的网站,没有很多时间去写博客,积累了很多的问题,几乎是一天一个,折腾死了,尤其是在模型方面几经周折. 以前,多半从事PHP开发,很少接触到模型(thinkphp中模型),但是 ...

  10. poj2594最小顶点覆盖+传递闭包

    传递闭包最开始是在Floyd-Warshall算法里面出现的,当时这算法用的很少就被我忽视了.. 传递闭包是指如果i能到达k,并且k能到达j,那么i就能到达j Have you ever read a ...