博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Web框架原理
阅读量:7042 次
发布时间:2019-06-28

本文共 4363 字,大约阅读时间需要 14 分钟。

前提

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

  1. request and response

  2. cookies and session

  3. template engine

  4. wsgi app and wsgi server

对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端。

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, sysenc, 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\r\n' % status))             for header in response_headers:                 out.write(wsgi_to_bytes('%s: %s\r\n' % header))             out.write(wsgi_to_bytes('\r\n'))        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!\n"# 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
本文转自 AltBoy 51CTO博客,原文链接:http://blog.51cto.com/altboy/1956784

转载地址:http://wweal.baihongyu.com/

你可能感兴趣的文章
HBase 管理,性能调优
查看>>
php 从1加到100
查看>>
centos 解决error: rpmdbNextIterator问题 (转)
查看>>
SQL Server--获取磁盘空间使用情况
查看>>
jquery操作select(增加,删除,清空)
查看>>
ELK学习总结(3-3)elk的组合查询
查看>>
(八十六)使用系统自带的分享框架Social.framework
查看>>
RMAN兼容性、控制文件自动备份、保存时间、备份策略、备份脚本(二)
查看>>
webpack入门
查看>>
Kubernetes-Host网络模式应用
查看>>
1.1 Introduction中 Putting the Pieces Together官网剖析(博主推荐)
查看>>
SOA并不能解决高并发事务
查看>>
9.6智力题(一)——给定两条绳子,每条绳子燃烧殆尽正好用一个小时,用这两条绳子准确计时15分钟...
查看>>
启动redis
查看>>
Swift 互斥锁写法
查看>>
matlab中元胞数组的创建与内容读取
查看>>
P3390 【模板】矩阵快速幂
查看>>
DateFormatUtil格式化时间
查看>>
RPi 2B QEMU 模拟树莓派
查看>>
Asp.net Web Api开发(第四篇)Help Page配置和扩展
查看>>