2018-06-11web框架编写

2018-06-11  本文已影响0人  菩灵

【web框架编写】05:14——框架:什么是web框架?为什么要有框架?
如果支持路径过多,需要写的单独的文件也会相应增多。
不同文件的application之间会有通用的工具。
不再把文件对应到路径中,而是整个网站全局只有一个如果,实现路由分发。
把“PATH_INFO”不对应到文件中,而是对应到application中的某一个部分上,由application进行调用。
只让web服务器加载一个文件,其中定义了一个application,建立路由信息(urls列表)进行映射,如果用户访问ctime.py执行ctime,如果访问sayhello.py执行sayhello。
目的是把多个文件压缩,只有一个入口Myweb.py,其中的application作为全局信息,能够被web服务器调用,在被调用的时候,用户请求信息放在env中,再去做映射。


Myweb.py中的application映射

如果使用框架,只在urls中加入映射。
框架:不用大规模改写,只在个别地方修改。

在web服务器程序中只提供一个py文件,里面的application映射多个py文件。


框架

符合WSGI协议的情况下, 文件中的application必须可以被调用(函数或者类),由于application函数中的代码不需要被改写,保持application代码不变,只修改属性,代码和行为不变,所以把它定义成一个类。
类中被实例的对象app需要被服务器调用,
一小时的视频看了好几遍,代码奉上:
web框架端(启动程序):

# coding:utf-8

import time
import sys
# 由于此文件是启动程序,所以需要从MyWebServer文件中导入
from MyWebServer import HTTPServer

sys.path.insert(1, './')


class Application(object):
    """框架的核心部分,也就是框架的主体程序,框架是通用的"""
    # 构造函数接收路由信息,放入对象中保存
    def __init__(self, urls):
        # 设置路由信息
        self.urls = urls

    # 由于HTTPServer把application当成函数,所以需要__call__方法
    def __call__(self, env, start_response):
        # 字典的索引方式区别:get方法如果不存在不会退
        # 出(不确定存在),[]方法会报异常(很确定存在)
        # 后面的“/”表示如果没传默认根路径
        path = env.get("PATH_INFO", "/")
        # 路由分发:找到对应路径的对应程序,你去执行
        for url, handler in self.urls:
            # "/ctime", show_time()
            if path == url:
                # handler是对应路径的函数
                # 调用__call__之后需要有返回值,
                # 这个返回值从执行的函数中得到
                # 一旦发现有比对值,直接返回,程序停止执行
                return handler(env, start_response) # 把函数返回的信息直接返回
                # 但别忘了后面的(env, start_response)两个参数
        # 应该等到都遍历之后发现没有才返回错误信息
        # 所以错误信息从此处开始404
        status = "404 Not Nound"
        headers = []
        start_response(status, headers)
        return "not found"


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


def say_hello(env, start_response):
    status = "200 OK"
    headers = [
        ("Conten-Type", "text/plain")
    ]
    start_response(status, headers)
    return "hello itcast"


if __name__ == "__main__":

    urls = [
        ("/", show_ctime),
        ("/ctime", show_ctime),
        ("/sayhello", say_hello)
    ]

    app = Application(urls)
    http_server = HTTPServer(app)  # 被明确导入了就可以直接用
    http_server.bind(8080)
    http_server.start()
    # 需要使用的时候,只需要更改urls路由信息

web服务器端:

# coding:utf-8

import socket
import sys
import re

from multiprocessing import Process
# 定义一个常量用来接收客户端发起的文件请求地址
# 设置静态文件根目录
HTML_ROOT_DIR = "./html"
WSGI_PYTHON_DIR = "./wsgipython"


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

    def start(self):
        self.server_socket.listen(128)
        while True:
            client_socket, client_address = self.server_socket.accept()
            print("[%s, %s]用户连接上了" % client_address)
            handle_client_process = Process(target=self.handle_client, args=(client_socket,))
            handle_client_process.start()
            client_socket.close()

    def start_response(self, status, headers):
        """
                 status = "200 OK"
            headers = [
                ("Content-Type", "text/plain")
            ]
            star
                """
        response_headers = "HTTP1.1 " + status + "\r\n"
        for header in headers:
            response_headers += "%s: %s\r\n" % header
        self.response_headers = response_headers



    def handle_client(self, client_socket):
        # 获取客户端请求
        request_data = client_socket.recv(1024)
        print(request_data)

        # 判断用户发来的请求
        # 使用splitlines来切割不同行
        request_lines = request_data.splitlines()
        for line in request_lines:
            print(line)

        # GET / HTTP/1.1
        request_start_line = request_lines[0]
        file_name = re.match(r"\w+ +(/[^ ]*) ", request_start_line.decode("utf-8")).group(1)
        method = re.match(r"(\w+) +/[^ ]* ", request_start_line.decode("utf-8")).group(1)

        """在对web服务器改写过程中,判断用户请求数据是动态资源还是静态资源通通不管"""

        # time.py
        env = {
            "PATH_INFO": file_name,
            "METHOD": method
        }
        # 所有以上信息都由app中的路由进行转发
        response_body = self.app(env, self.start_response)

        response = self.response_headers + "\r\n" + response_body

        # 向客户端形响应数据
        client_socket.send(bytes(response, "utf-8"))
        # 关闭客户端连接
        client_socket.close()

    def bind(self, port):
        self.server_socket.bind(("", port))


def main():
    sys.path.insert(1, WSGI_PYTHON_DIR)
    http_server = HTTPServer()
    # http_server.set_port()
    http_server.bind(8080)
    http_server.start()


if __name__ == "__main__":
    main()
上一篇 下一篇

猜你喜欢

热点阅读