深入WSGI,并按样例实现一个

感觉WSGI确实和SERVLET相似,为PYTHON提供了运行和管理环境。WSGI服务器和PYTHON的WEB框架一起,实现WEB响应。

 

步骤:

  • 首先,服务器启动并加载一个由Web框架/应用提供的可调用的’application’
  • 然后,服务器读取请求
  • 然后,服务器解析它
  • 然后,服务器使用请求的数据创建了一个’environ’字典
  • 然后,服务器使用’environ’字典和’start_response’做为参数调用’application’,并拿到返回的响应体。
  • 然后,服务器使用调用’application’返回的数据,由’start_response’设置的状态和响应头,来构造HTTP响应。
  • 最终,服务器把HTTP响应传回给户端。 

代码(别小看它,启动DJANGO的APP都可以的,但DJANGO必须提供一个WSGI供它调用APP):

# Tested
import socket
import StringIO
import sys

class WSGIServer(object):

    address_family = socket.AF_INET
    socket_type = socket.SOCK_STREAM
    request_queue_size = 1

    def __init__(self, server_address):
        # Create a listening socket
        self.listen_socket = listen_socket = socket.socket(
            self.address_family,
            self.socket_type
        )
        # Allow to reuse the same address
        listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        # Bind
        listen_socket.bind(server_address)
        # Activate
        listen_socket.listen(self.request_queue_size)
        # Get server host name and port
        host, port = self.listen_socket.getsockname()[:2]
        self.server_name = socket.getfqdn(host)
        self.server_port = port
        # Return headers set by Web framework/Web application
        self.headers_set = []

    def set_app(self, application):
        self.application = application

    def serve_forever(self):
        listen_socket = self.listen_socket
        while True:
            # New client connection
            self.client_connection, client_address = listen_socket.accept()
            # Handle one request and close the client connection. Then
            # loop over to wait for another client connection
            self.handle_one_request()

    def handle_one_request(self):
        self.request_data = request_data = self.client_connection.recv(1024)
        # Print formatted request data a la 'curl -v'
        print(''.join(
            '> {line}n'.format(line=line)
            for line in request_data.splitlines()
        ))

        self.parse_request(request_data)

        # Construct environment dictionary using request data
        env = self.get_environ()

        # It's time to call our application callable and get
        # back a result that will become HTTP response body
        result = self.application(env, self.start_response)

        # Construct a response and send it back to the client
        self.finish_response(result)

    def parse_request(self, text):
        request_line = text.splitlines()[0]
        request_line = request_line.rstrip('rn')
        # Break down the request line into components
        (self.request_method,  # GET
         self.path,            # /hello
         self.request_version  # HTTP/1.1
         ) = request_line.split()

    def get_environ(self):
        env = {}
        # The following code snippet does not follow PEP8 conventions
        # but it's formatted the way it is for demonstration purposes
        # to emphasize the required variables and their values
        #
        # Required WSGI variables
        env['wsgi.version']      = (1, 0)
        env['wsgi.url_scheme']   = 'http'
        env['wsgi.input']        = StringIO.StringIO(self.request_data)
        env['wsgi.errors']       = sys.stderr
        env['wsgi.multithread']  = False
        env['wsgi.multiprocess'] = False
        env['wsgi.run_once']     = False
        # Required CGI variables
        env['REQUEST_METHOD']    = self.request_method    # GET
        env['PATH_INFO']         = self.path              # /hello
        env['SERVER_NAME']       = self.server_name       # localhost
        env['SERVER_PORT']       = str(self.server_port)  # 8888
        return env

    def start_response(self, status, response_headers, exc_info=None):
        # Add necessary server headers
        server_headers = [
            ('Date', 'Tue, 31 Mar 2015 12:54:48 GMT'),
            ('Server', 'WSGIServer 0.2'),
        ]
        self.headers_set = [status, response_headers + server_headers]
        # To adhere to WSGI specification the start_response must return
        # a 'write' callable. We simplicity's sake we'll ignore that detail
        # for now.
        # return self.finish_response

    def finish_response(self, result):
        try:
            status, response_headers = self.headers_set
            response = 'HTTP/1.1 {status}rn'.format(status=status)
            for header in response_headers:
                response += '{0}: {1}rn'.format(*header)
            response += 'rn'
            for data in result:
                response += data
            # Print formatted response data a la 'curl -v'
            print(''.join(
                '> {line}n'.format(line=line)
                for line in response.splitlines()
            ))
            self.client_connection.sendall(response)
        finally:
            self.client_connection.close()

SERVER_ADDRESS = (HOST, PORT) = '', 8888

def make_server(server_address, application):
    server = WSGIServer(server_address)
    server.set_app(application)
    return server

if __name__ == '__main__':
    if len(sys.argv) < 2:
        sys.exit('Provide a WSGI application object as module:callable')
    app_path = sys.argv[1]
    module, application = app_path.split(':')
    module = __import__(module)
    application = getattr(module, application)
    httpd = make_server(SERVER_ADDRESS, application)
    print('WSGIServer: Serving HTTP on port {port} ...n'.format(port=PORT))
    httpd.serve_forever()
def app(environ, start_response):
    status = '200 OK'
    response_headers = [('Content-Type', 'text/plain')]
    start_response(status, response_headers)
    return ['Hello world from a simple WSGI application!n']

 

截图:

时间: 2024-07-29 13:13:28

深入WSGI,并按样例实现一个的相关文章

一个MYSQL样例数据库

    本节介绍一个样例数据库,这个数据库在本书各个部分都可能用到.在学习将MySQL投入工作时,这个数据库为您提供了参考的例子.我们主要从前面描述过的两种情形来给出例子:    ■ 机构的秘书方案.我们需要一些比"机构"更为明确的信息,所以现在就来构造一个,它具有这样一些特性:它由为了研究美国历史这个共同目的而聚集在一起的一群人组成(一时找不到更好的名称,就暂且称为美国历史同盟).在交会费的基础上定期更新各会员的资格.会费构成了此同盟的活动经费,如出版报纸"美国嗄昀薄4肆

discuz!-客户想做一个比较有个性的论坛社区,而用discuz与dedecms做的样例又不太满意,该怎么办?

问题描述 客户想做一个比较有个性的论坛社区,而用discuz与dedecms做的样例又不太满意,该怎么办? 因为可能是前期沟通的问题,订单是接下来,客户也负款了,而技术人员招进来后, 说客户要求是无法通地discuz与dedecms做的,只能开发,但这样费用会特别高? 怎么办,难道discuz与dedecms不能做出客户所需要的页面效果吗?还是技术人员的 技术还有掌握好? 解决方案 discuz和dedecms是可以自定义页面模板的(只是外观,但功能如果有特殊需求可能要自己改),我觉得你们竟然招

一个零售业样例使用RACI矩阵进行信息治理

在处理与信息相关的角色和职责方面,组织往往举步维艰.我们常会听到这样一些问题:"谁拥有那些数据?"."数据管理员在组织中应该处于怎样的位置?"."谁应该加入信息治理委员会?". RACI 矩阵是一种能够通过基于事实的方式解决这些问题的优秀工具."RACI"这个缩写词的含义如下:  负责 (Responsible):指定负责管理一项属性的人员.一个属性可能有多个负责方. 当责 (Accountable):最终承担数据属性责任

MaxCompute模板与样例

1. 简介 MaxCompute : 是一种快速.完全托管的数据仓库解决方案,用户可以通过SQL, MR, UDF等接口与其交互. MaxCompute Studio : 是MaxCompute平台提供的安装在开发者客户端的大数据集成开发环境(IDE),是用户与MaxCompute交互的高效工具. 代码模板:让用户更加高效的写一些固定模式的代码,简化很多重复的代码,以提高编码效率. 代码示例:一例胜千言,帮助用户快速熟悉语法,可参考示例编写自己的程序,快速上手. 代码模板和示例是用户熟悉新产品和

JAVA的输入输出基本操作样例

这些类的继承关系有些类似,弄一个作为样例,理解一下其中的机制. package cc.openhome; import java.io.*; public class Member { private String number; private String name; private int age; public Member(String number, String name, int age) { this.number = number; this.name = name; thi

多线程分别定时读写同一个文件的样例

两个线程,一个每分钟写入当前时间到指定文件,另一个线程读出每分钟新写的内容. 使用简单的Thread.sleep技术实现定时 package test.thread; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.util.Date; /** * 多线程读写同一个文件的样例. * * @author 赵学庆

大部分数据挖掘算法都将选取的样例、误差默认为服从高斯分布

问题描述 大部分数据挖掘算法都将选取的样例.误差默认为服从高斯分布 大部分数据挖掘算法都将选取的样例.误差默认为服从高斯分布,这样对数据挖掘结果的精确度影响到底有多大?甚至是这种默认是不是根本就不对? 说服从高斯分布是大量统计的结果,然后就将不明白具体分布的一些样例都默认为高斯分布,总感觉不是很靠谱啊? 解决方案 晕,高斯分布,我们一般都叫做正态分布好不好.正态分布是最符合自然情况的分布形态. 好比你要选取一个班级学生的成绩样本,如果是随机选取的,肯定是高分和不及格的少,成绩中等的多. 模拟一组

任务调度SchedulerX系列之QuartZ时间表达式语法与样例说明

目   录 Quartz时间表达式入门... 1 Quartz时间表达式格式详解... 2 Quartz表达式中的特殊字符... 3 * 星号... 3 ? 问号... 3 , 逗号... 4 / 斜杠... 4 - 中划线... 5 L 字母... 5 W 字母... 6 # 井号... 6 QuartZ时间表达式样例... 7 分钟的 Cron 表达式... 7 天的 Cron 表达式... 7 周和月的 Cron 表达式... 7       Quartz时间表达式入门 时间格式 <s m

MariaDB:安装、配置、JAVA源代码样例

      MariaDB的目的是完全兼容MySQL,包括API和命令行,使之能轻松成为MySQL的代替品.在存储引擎方面,使用XtraDB来代替MySQL的InnoDB.         MariaDB由MySQL的创始人麦克尔·维德纽斯主导开发,他早前曾以10亿美元的价格,将自己创建的公司MySQL AB卖给了SUN,此后,随着SUN被甲骨文收购,MySQL的所有权也落入Oracle的手中.MariaDB名称来自麦克尔·维德纽斯的女儿玛丽亚(英语:Maria)的名字 1.设置yum源 参考: