day 021 mini_WEB框架_路由

基础代码
服务器
from socket import *
import multiprocessing
import re

import wsgi_5

class WEB_Server(object):
    def __init__(self):
        """初始化服务器"""
        # 创建一个服务器套接字
        self.server_soc = socket(AF_INET, SOCK_STREAM)
        # 使得套接字关闭后,端口可以立即释放,立即连接
        self.server_soc.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
        # 绑定服务器套接字的ip地址和端口,转为监听状态
        self.server_soc.bind(('', 1314))
        self.server_soc.listen(128)

    def handle_request(self, client_soc):
        # 接收客户端传来的请求
        recv_data = client_soc.recv(1024).decode("utf-8")
        print("客户端文件接收成功:\r\n", recv_data)
        if recv_data:
            # 提取出请求的文件路径
            first_line = recv_data.splitlines()[0]
            content_path = re.match(r'[^/]+(/[^ ]*)', first_line).group(1)

            # 响应请求
            if content_path == '/':
                content_path = "/index.html"
            # 如果搜索的内容路径为.py文件,动态返回,否则静态返回
            if content_path.endswith(".py"):
                # 返回动态数据
                # 空字典
                params_server = dict()
                # 添加一个地址
                params_server['url'] = content_path
                body = wsgi_5.application(params_server, self.set_head_params)
                # 这个是返回一个头数据以后才能拼接
                head = "HTTP/1.1 %s\r\n" % self.stauts
                # 拼接头部
                for temp in self.params:
                    head += "%s:%s\r\n" % (temp[0], temp[1])
                # 拼接响应内容
                content = head + "\r\n" + body
                client_soc.send(content.encode('utf-8'))
            else:
                #返回静态数据
                try:
                    # 获取到文件内容
                    with open('html' + content_path, 'rb') as file:  # 本地文件夹直接找名字,不需要在之前加‘/’
                        content = file.read()
                except:
                    # 文件不存在
                    responce_head = "HTTP/1.1 404 NOT FOUND\r\n"
                    responce_head += 'Content-Type: text/html;charset=utf-8\r\n'
                    responce_head += "\r\n"
                    responce_body = "没有找到内容"
                    client_soc.send(responce_head.encode("utf-8"))
                    client_soc.send(responce_body.encode("utf-8"))
                else:
                    # 返回网页给浏览器
                    responce_head = "HTTP/1.1 200 OK\r\n"
                    responce_head += "\r\n"
                    responce_body = content
                    client_soc.send(responce_head.encode("utf-8"))
                    client_soc.send(responce_body)

        # 关闭子进程p1的客服套接字(主进程中客服套接字的硬链接)
        client_soc.close()

    def run_server(self):
        while True:
            # 等待客户端连接
            print("等待客户端连接")
            client_soc, client_addr = self.server_soc.accept()
            print("客户端连接成功 %s" % client_addr[0])

            # 与客户端进行通信
            # 创建子进程并启动
            p = multiprocessing.Process(target=self.handle_request, args=(client_soc,))
            p.start()
            # 关闭主进程的客服套接字
            client_soc.close()  # 进程是互相独立的,需要也在主进程中关闭套接字

        # # 关闭套接字
        # server_soc.close()

    def set_head_params(self,stauts,params):
        self.stauts = stauts
        self.params = params

def main():
    """服务器主逻辑"""
    # 创建服务器对象
    web_server = WEB_Server()
    # 开启服务器
    web_server.run_server()


if __name__ == '__main__':
    main()
miniWEB框架
# 定义一个application函数,获取服务器传来的待处理数据及设置响应头函数引用,完成导入响应头信息,返回响应体信息的功能
# 定义函数
def application(environ, start_responce):
# 启动导入响应头信息函数
    start_responce("200 ok", [('Content-Type', 'test/html')])
# 对待处理数据进行处理后,返回响应体信息
    url = environ['file_name']
    if url == "index.py":
        return "this is index.py"
    elif url == "center.py":
        return "this is center.py"
    else:
        return "no file found"

封装网页信息代码

  • 在实际开发中,是将前端的html代码作为响应体传给浏览器的
  • 可以使用函数封装代码,主逻辑会清晰一些,但是,还是需要把网页信息整个放在函数里
    这里写图片描述
  • 但是不利用前端更改使用,那么就使用with open打开相应文件,会更易于阅读而且不耽误文件信息的更改。
    这里写图片描述
    • 但是当页面比较多时,会写出很多的if,elif语句,不好,一般多于三个if分支,就要考虑其他方式

用字典返回响应方法

  • 为了解决多页面问题。引入字典的使用,可以所有有效的文件路径和相应函数引用放在一个字典里
  • 需要返回某个页面时,只需要遍历字典,判断请求的文件路径匹配字典中的哪一个键,取出对应的值,调用响应函数即可
    这里写图片描述

完后路由功能

  • 需要把所有的路径和函数引用一一输入到字典中,还是比较麻烦,有没有更方便快捷的办法?
  • 有! 给装饰器传参,使用插拔式的路由功能!
    • 装饰器是指,在不改变原函数体的,正常调用原函数的的情况下,给函数增加新的功能
    • 在装饰器的基础上,可以再给装饰器传递一个参数(文件的路径),这样就可以在程序执行到定义函数的时候,就自动给预先定义的字典生成了一个键值对(该键值对对应一个页面请求的路径和调用文件函数引用)
    • 注意路由实现代码里,最好把函数引用存储为第二层函数的引用,这样,方便后期对函数添加功能
      这里写图片描述

完整mini_WEB框架_路由

代码

import re

# 定义存请求文件路径和响应函数引用的对应键值对
body_dict = {}
# 定义路由,即在装饰器的基础上再加一层函数,作用是传递一个参数,返回@set_fun
def route(url):
    def set_fun(func):
        def call_fun(*args, **kwargs):
            return func(*args, **kwargs)
        body_dict[url] = call_fun
        return call_fun
    return set_fun

# 输出index.html页面
@route("/index.html") # 使用路由
def index():
    with open("./templates/index.html") as f:
        content = f.read()
    row_str = """<tr>
        <td>1</td>
        <td>000007</td>
        <td>全新好</td>
        <td>10.01%</td>
        <td>4.40%</td>
        <td>16.05</td>
        <td>14.60</td>
        <td>2017-07-18</td>
        <td>
            <input type="button" value="添加" id="toAdd" name="toAdd" systemidvaule="000007">
        </td>
        </tr>"""
    content_new = re.sub(r'\{%content%\}', row_str, content)
    return content_new

# 输出center.html页面
@route("/center.html")
def center():
    with open("./templates/center.html") as f:
        content = f.read()
    row_str = """
<tr>
            <td>000036</td>
            <td>华联控股</td>
            <td>10.04%</td>
            <td>10.80%</td>
            <td>11.29</td>
            <td>10.26</td>
            <td>123</td>
            <td>
                <a type="button" class="btn btn-default btn-xs" href="/update/000036.html"> <span class="glyphicon glyphicon-star" aria-hidden="true"></span> 修改 </a>
            </td>
            <td>
                <input type="button" value="删除" id="toDel" name="toDel" systemidvaule="000036">
            </td>
        </tr>
    """
    content_new = re.sub(r'\{%content%\}', row_str, content)
    return content_new

# 输出update.html页面
@route("/update.html")
def update():
    with open("./templates/update.html") as f:
        content = f.read()
    return content


# WSGI协议
def application(environ, start_response):
    # 传回响应头信息
    start_response('200 OK', [('Content-Type', 'text/html;charset=utf-8')])
    # 取出请求的文件路径
    url = environ['url']
    # 返回body值
    try:
        # 匹配到响应函数,执行,即可返回相应文件内容
        return body_dict[url]() 
    except Exception as e:
        # 没有匹配到,返回提示页面
        return "no page was found"

总结

  • 路由功能,即通过一个地址,找到一个页面
  • 其实,就是AOP编程(面向切面编程)思想的一个运用,让我们只需要关心当前业务功能的实现,不需要关注整个程序的代码逻辑
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值