动态服务器以及WSGI

服务器动态资源请求

1. 浏览器请求动态页面过程

 

2. WSGI

怎么在你刚建立的Web服务器上运行一个Django应用Flask应用,如何不做任何改变而适应不同的web架构呢?

在以前,选择 Python web 架构会受制于可用的web服务器,反之亦然。如果架构和服务器可以协同工作,那就好了:

 但有可能面对(或者曾有过)下面的问题,当要把一个服务器和一个架构结合起来时,却发现他们不是被设计成协同工作的:

那么,怎么可以不修改服务器和架构代码而确保可以在多个架构下运行web服务器呢?答案就是 Python Web Server Gateway Interface (或简称 WSGI,读作“wizgy”)。

WSGI允许开发者将选择web框架和web服务器分开。可以混合匹配web服务器和web框架,选择一个适合的配对。比如,可以在Gunicorn 或者 Nginx/uWSGI 或者 Waitress上运行 Django, Flask, 或 Pyramid。真正的混合匹配,得益于WSGI同时支持服务器和架构:

 

 

web服务器必须具备WSGI接口,所有的现代Python Web框架都已具备WSGI接口,它让你不对代码作修改就能使服务器和特点的web框架协同工作。

WSGI由web服务器支持,而web框架允许你选择适合自己的配对,但它同样对于服务器和框架开发者提供便利使他们可以专注于自己偏爱的领域和专长而不至于相互牵制。其他语言也有类似接口:java有Servlet API,Ruby 有 Rack。

3.定义WSGI接口

WSGI接口定义非常简单,它只要求Web开发者实现一个函数,就可以响应HTTP请求。我们来看一个最简单的Web版本的“Hello World!”:

def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return 'Hello World!'

上面的application()函数就是符合WSGI标准的一个HTTP处理函数,它接收两个参数:

  • environ:一个包含所有HTTP请求信息的dict对象;
  • start_response:一个发送HTTP响应的函数。

整个application()函数本身没有涉及到任何解析HTTP的部分,也就是说,把底层web服务器解析部分和应用程序逻辑部分进行了分离,这样开发者就可以专心做一个领域了

不过,等等,这个application()函数怎么调用?如果我们自己调用,两个参数environ和start_response我们没法提供,返回的str也没法发给浏览器。

所以application()函数必须由WSGI服务器来调用。有很多符合WSGI规范的服务器。而我们此时的web服务器项目的目的就是做一个极可能解析静态网页还可以解析动态网页的服务器

接下来是我写的服务器+框架:

服务器:MyWebServer.py

#-*-coding:utf-8-*-
import sys
import re
from socket import *
from multiprocessing import Process
from My_Web_Framework import Application

#设置静态文件根目录
HTTP_ROOT_DIR = "./html"

WSGI_PYTHON_DIR = "./wsgipython"

class HTTPServer(object):
    ''''''
    def __init__(self, application):
        """构造函数,application是框架函数"""
        self.app = application
        self.tcp_socket = socket(AF_INET, SOCK_STREAM)
        self.tcp_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)


    def start(self):
        self.tcp_socket.listen(128)
        while True:
            try:
                cli_socket, addrs = self.tcp_socket.accept()
                print("%s  %s:用户已连接" % (addrs[0], addrs[1]))
                p = Process(target=self.handle_client, args=(cli_socket,))
                p.start()
                cli_socket.close()
            except:
                print("服务器已经关闭")
                cli_socket.close()

        tcp_socket.close()

    def start_response(self, status, headers):
        self.response_start = "HTTP/1.1 " + status + "\r\n"
        server_headers = ""
        for header in headers:
            server_headers += "%s: %s\r\n"%header
        self.response_headers = server_headers

    def handle_client(self,cli_socket):
        # 接收数据
        request_data = cli_socket.recv(1024)
        # 解析HTTP报文协议 request_data
        print("requst_data:", request_data)

        # 处理响应数据
        request_lines = request_data.splitlines()
        print(request_lines)
        request_da = request_lines[0]
        # 获取用户想要的请求名
        file_name = re.match(r"\w+ +(/[^ ]*) ", request_da.decode("utf-8")).group(1)
        #method = re.match(r"\w+ +/[^ ]* ", request_da.decode("utf-8")).group(1)
        env = {
            "PATH_INFO": file_name
            #"METHOD": method
        }
        response_body = self.app(env, self.start_response)
        response_start_line = self.response_start
        response_header = self.response_headers

        response = response_start_line + response_header + "\r\n" + response_body
        # 发送数据
        cli_socket.send(bytes(response, "utf-8"))
        # cli_socket.send(response)

        # 关闭套接字
        cli_socket.close()
        print("链接已经断开")

    def bind(self, port):
        self.tcp_socket.bind(port)


def main():
    sys.path.insert(1,WSGI_PYTHON_DIR)
    if len(sys.argv) < 2:
        sys.exit("python MyWebServer.py Module:app")
    # 适应性导入
    # python MyWebServer.py My_Web_Framework:app
    module_name, app_name = sys.argv[1].split(":")
    # module_name = "My_Web_Framework"
    # app_name = "app"
    # 动态导入模块
    m = __import__(module_name)
    app = getattr(m, app_name)

    http_server = HTTPServer(app)
    http_server.bind(("",8000))
    http_server.start()

if __name__ == '__main__':
    main()

框架My_Web_Framework.py

import time

# from MyWebServer import HTTPServer

HTTP_ROOT_DIR = "./html"

class Application(object):
    """"""
    def __init__(self, urls):
        self.urls = urls
    def __call__(self, env, start_response):
        #路由分发
        path = env.get("PATH_INFO", "/")
        print(path)
        if path.startswith("/static"):
            # 要访问静态文件 访问方式为ip:端口/static/index.html
            file_name = path[7:]
            try:
                f = open(HTTP_ROOT_DIR + file_name, "rb")
                file_data = f.read()
                f.close()
            except IOError:
                start_response("404 Not Found", [])
                return "Not Found"
            else:
                # 构造响应数据
                status = "200 OK"
                response_header = [
                    ("Server","My server")
                ]
                start_response(status,response_header)
                return file_data.decode("utf-8")
        else:
            for url, handler in self.urls:
                print(url, " ", path,"\n**************\n")
                if path == url:
                    return handler(env, start_response)
        start_response("404 Not Found", [])
        return "Not Found"

def show_ctime(env, start_response):
    status = "200 OK"
    headers = [
        ("Content", "text/plain")
    ]
    start_response(status, headers)
    return time.ctime()

urls = [
    ("/", show_ctime),
    ("/ctime", show_ctime)
]
app = Application(urls)
# if __name__ == "__main__":
#     urls = [
#         ("/", show_ctime),
#         ("/ctime", show_ctime)
#     ]
#     app = Application(urls)
#     http_server = HTTPServer(app)
#     http_server.bind(("", 8000))
#     http_server.start()

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值