zoukankan      html  css  js  c++  java
  • Bottle源码阅读笔记(一):WSGI

    前言

    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的实现分两个部分,一是服务器,二是应用程序。下面来看一看它们各自是什么样子的,以及两者之间是如何协作的。

     1 class Server:
     2 
     3     def __init__(self, server_address):
     4         self.server_address = server_address
     5 
     6     def set_app(self, application):
     7         self.app = application
     8 
     9     def serve_forever(self):
    10         while True:
    11             # socket.accept()
    12             if request_comein():
    13                 self.handle_request()
    14 
    15     def handle_request(self):
    16         request_data = self.get_request()
    17         self.parse_request(request_data)
    18         environ = self.get_environ()
    19         result = self.application(environ, self.start_response)
    20         self.send_response(result)
    21 
    22     def start_response(self, status, headers, exc_info):
    23         pass
    24 
    25     def get_environ(self):
    26         pass
    27 
    28     def get_request(self):
    29         pass
    30 
    31     def parse_request(self, text):
    32         pass
    33 
    34     def send_response(self, message):
    35         pass
    36 
    37 
    38 def make_server(host, port, app, server=Server):
    39     server = server((host, port))
    40     server.set_app(app)
    41     return server
    42 
    43 def simple_app(environ, start_response):
    44     status = '200 OK'
    45     response_headers = [('Content-type', 'text/plain')]
    46     start_response(status, response_headers)
    47     return 'Hello World!'
    48 
    49 if __name__ == '__main__':
    50     server = make_server('localhost', 8080, simple_app)
    51     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应用是什么样子的,如何运行,跟我们的模型有什么区别。

    1 from bottle import Bottle, run
    2 
    3 app = Bottle()
    4 
    5 @app.route('/hello')
    6 def hello():
    7     return 'Hello World!'
    8 
    9 run(app, host='localhost', port=8080, server='wsgiref')

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

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

    1 def __call__(self, environ, start_response):
    2     ''' Each instance of :class:'Bottle' is a WSGI application. '''
    3     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函数和适配器部分代码:

     1 def run(app=None, server='wsgiref', host='127.0.0.1', port=8080,
     2         interval=1, reloader=False, quiet=False, plugins=None,
     3         debug=None, **kargs):
     4     if server in server_names:
     5         server = server_names.get(server)
     6     if isinstance(server, basestring):
     7         server = load(server)
     8     if isinstance(server, type):
     9         server = server(host=host, port=port, **kargs)
    10     if not isinstance(server, ServerAdapter):
    11         raise ValueError("Unknown or unsupported server: %r" % server)
    12     ...
    13     server.run(app)
    14 
    15 class MeinheldServer(ServerAdapter):
    16     def run(self, handler):
    17         from meinheld import server
    18         server.listen((self.host, self.port))
    19         server.run(handler)

    最后

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

    作者:RainFD
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
  • 相关阅读:
    webpack打包报错configuration has an unknown property 'mode'
    CSP 201712-4 行车路线(最短路)
    设计模式
    sqlserver 迁移数据
    DataX
    Python 对接WebService
    IOS APP打包流程
    nginxUI
    ROS脚本-下线时判断在线数量进行重拨号
    bash 字符串截取的8种方法
  • 原文地址:https://www.cnblogs.com/rainfd/p/bottle1.html
Copyright © 2011-2022 走看看