zoukankan      html  css  js  c++  java
  • Python web框架总结

    web框架总结

    前提

    一个web框架需要包含的组件或者功能有:

    1. router
    2. orm
    3. request and response
    4. cookies and session
    5. template engine
    6. wsgi app and wsgi server

    wsgi

    首先要了解WSGI的相关知识,如下:

    • web server:指的是软件程序,它从客户端接受请求,然后返回一个Response,需要注意的是它不创建Response,web app才是创建Response的主体。
    • web app:根据url来创建响应并将响应传回给web server。
    • WSGI:是一个规范,描述了web server如何与web app交互、web app如何处理请求,它规定每个app必须是一个可调用的对象(方法或者类),接受两个参数environ和start_response。

    实现

    web server

    environ和start_response都是服务器提供的,所以服务端这边需要提供如下:

    1. 准备environ参数;
    2. 定义start_response函数;
    3. 调用程序端的可调用对象;

    代码具体如下(取自PEP 333):

    import os, sys
    enc, esc = sys.getfilesystemencoding(), 'surrogateescape'
    def unicode_to_wsgi(u):
        # Convert an environment variable to a WSGI "bytes-as-unicode" string
        return u.encode(enc, esc).decode('iso-8859-1')
    def wsgi_to_bytes(s):
        return s.encode('iso-8859-1')
    def run_with_cgi(application):
        # environ参数,里面是HTTP请求的环境变量
        environ = {k: unicode_to_wsgi(v) for k,v in os.environ.items()}
        environ['wsgi.input']        = sys.stdin.buffer
        environ['wsgi.errors']       = sys.stderr
        environ['wsgi.version']      = (1, 0)
        environ['wsgi.multithread']  = False
        environ['wsgi.multiprocess'] = True
        environ['wsgi.run_once']     = True
        if environ.get('HTTPS', 'off') in ('on', '1'):
            environ['wsgi.url_scheme'] = 'https'
        else:
            environ['wsgi.url_scheme'] = 'http'
        headers_set = []
        headers_sent = []
        # 将应答的数据输出到终端
        def write(data):
            out = sys.stdout.buffer
            if not headers_set:
                 raise AssertionError("write() before start_response()")
            elif not headers_sent:
                 # Before the first output, send the stored headers
                 status, response_headers = headers_sent[:] = headers_set
                 out.write(wsgi_to_bytes('Status: %s
    ' % status))
                 for header in response_headers:
                     out.write(wsgi_to_bytes('%s: %s
    ' % header))
                 out.write(wsgi_to_bytes('
    '))
            out.write(data)
            out.flush()
        # 根据程序传过来的状态和头部参数设置响应的状态和头部
        def start_response(status, response_headers, exc_info=None):
            if exc_info:
                try:
                    if headers_sent:
                        # Re-raise original exception if headers sent
                        raise exc_info[1].with_traceback(exc_info[2])
                finally:
                    exc_info = None     # avoid dangling circular ref
            elif headers_set:
                raise AssertionError("Headers already set!")
            headers_set[:] = [status, response_headers]
            return write
        # 调用客户端的对象,并且输出返回的结果
        result = application(environ, start_response)
        try:
            for data in result:
                if data:    # don't send headers until body appears
                    write(data)
            if not headers_sent:
                write('')   # send headers now if body was empty
        finally:
            if hasattr(result, 'close'):
                result.close()
    

    web app

    因为服务端和客户端需要共同遵守WSGI协议内容,所以客户端这边需要使用到服务端提供的environ和start_response,web app需要返回的类型需要是可迭代的。这里分为三种类型的实现,分别是函数,类,实例;

    函数

    HELLO_WORLD = b"Hello world!
    "
    # 1. 可调用对象是一个函数
    def application(environ, start_response):
        # HTTP response code and message
        status = '200 OK'
        # 应答的头部是一个列表,每对键值都必须是一个 tuple。
        response_headers = [('Content-Type', 'text/plain'),
                            ('Content-Length', str(len(HELLO_WORLD)))]
        # 调用服务器程序提供的 start_response,填入两个参数
        start_response(status, response_headers)
        # 返回必须是 iterable
        return [HELLO_WORLD]
    

    # 2. 可调用对象是一个类
    class AppClass:
        """这里的可调用对象就是 AppClass 这个类,调用它就能生成可以迭代的结果。          使用方法类似于:
            for result in AppClass(env, start_response):
                 do_somthing(result)
        """
        def __init__(self, environ, start_response):
            self.environ = environ
            self.start = start_response
        def __iter__(self):
            status = '200 OK'
            response_headers = [('Content-type', 'text/plain')]
            self.start(status, response_headers)
            yield HELLO_WORLD
    

    实例

    # 3. 可调用对象是一个实例
    class AppClass:
        """这里的可调用对象就是 AppClass 的实例,使用方法类似于:
            app = AppClass()
            for result in app(environ, start_response):
                 do_somthing(result)
        """
        def __init__(self):
            pass
        def __call__(self, environ, start_response):
            status = '200 OK'
            response_headers = [('Content-type', 'text/plain')]
            self.start(status, response_headers)
            yield HELLO_WORLD
  • 相关阅读:
    已开启博客园~
    友链
    javacv 接收RTSP流(或avi/mp4视频文件),输出byte[]
    Springboot项目中,使用logback来管理日志。
    PPT文件流转为图片,并压缩成ZIP文件输出到指定目录
    通过AOP自定义注解实现记录用户操作日志。
    使用javacv,解码socket接收的H264码流(byte[]),转为yuv处理,最后再合成转为H264
    idea 开始java之旅
    浅谈Winform控件开发(一):使用GDI+美化基础窗口
    WinformGDI+入门级实例——扫雷游戏(附源码)
  • 原文地址:https://www.cnblogs.com/George1994/p/7368388.html
Copyright © 2011-2022 走看看