8 Python高级 mini-web框架

本文详细描述了浏览器请求动态页面时,Web服务器如何根据文件扩展名判断静态或动态资源,并通过WSGI协议调用相应函数处理。涉及多进程编程,展示了如何在服务器中解耦逻辑与资源访问,以及如何设置HTTP响应头和发送数据给浏览器。
摘要由CSDN通过智能技术生成

浏览器请求动态页面过程

一个浏览器请求一个资源的时候 web服务器一定会根据相应的判断条件 如果判断是动态的 就调用框架里面的application函数 当这个函数调用完的时候 需要返回一个body

多进程 面向对象 web服务器:

import socket
import multiprocessing
import re

class WSGIServer(object):
    def __init__(self):#创建对象的时候 套接字就创好
        # 1 创建套接字
        self.tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 设置套接字 让套接字可以重复利用这个资源
        self.tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        # 2 绑定
        self.tcp_server_socket.bind(('', 7878))
        # 3 默认套接字主动改为被动
        self.tcp_server_socket.listen(128)

    def send_data(self,new_socket):  # 为这个客户端返回数据
        # 1 接受浏览器发送过来的请求 即http请求
        # GET / HTTP/1.1
        # .....
        request = new_socket.recv(1024).decode('utf-8')
        print(request)
        request_line = request.splitlines()
        print(request_line)  # 返回的是一个列表
        ret = re.match(r'[^/]+(/[^ ]*)', request_line[0])  # GET /index.html HTTP.1.1
        if ret:
            file_name = ret.group(1)  # 提取客户端想要的html文件名
            if file_name == '/':
                file_name = '/index.html'  # 如果没有输入页面 就默认index.html当作页面

        # 2 返回http格式的数据 给浏览器

        try:
            # 打开想要的文件
            f = open(file_name, 'rb')  # 二进制的形式直接读取 后面就不用编码了
        except:  # 找不到文件就返回NOT FOUND
            response = 'HTTP/1.1 404  NOT FOUND\r\n'
            response += '\r\n'
            response += '-----not found---'
            new_socket.send(response.encode('utf-8'))
        else:  # 如果能打开文件就读取并发送
            html_contend = f.read()
            f.close()
            # 2.1 准备发送给浏览器的数据---header
            response = "HTTP/1.1 200 OK\r\n"
            response += '\r\n'  # 空行加body
            # response += '<b1>hehehe</b1>'#2.2 发送给浏览器的数据body
            new_socket.send(response.encode('utf-8'))
            new_socket.send(html_contend)  # 不能和response一起发过去 因为是二进制的

        new_socket.close()


    def run_forever(self):

        while True:
            # 4 等待客户端连接
            new_socket, client_add = self.tcp_server_socket.accept()

            # 多进程
            # 不用多进程的时候 需要等待服务完之后才能服务下一个
            # 可以在接受连接的时候开一个进程 让进程里面的线程服务
            # accept还是一个 分配任务的时候多个人去做
            p = multiprocessing.Process(target=self.send_data, args=(new_socket,))  # 5 为这个客户端服务
            p.start()
            new_socket.close()  # 需要再次关闭 因为子进程会复制父进程的资源 在创建进程之前的父进程的所有变量都会被复制一份
            # 所以子进程中也有new_socket 但是都标记的一个客户端

            ##5 为这个客户端服务
            # send_data(new_socket)
        # 6 关闭监听套接字
        tcp_server_socket.close()
def main():
    wsgi_server = WSGIServer()
    wsgi_server.run_forever()

if __name__ == "__main__":
    main()

实际中的数据请求:

 修改之前的代码的2 返回http格式数据这段代码:

        # 2 返回http格式的数据 给浏览器
        #2.1 如果请求的资源不是以.py结尾 那么就认为是静态资源(html/css/js/png jpg等)
        if not file_name.endswith(".py"):
            try:
                # 打开想要的文件
                f = open(file_name, 'rb')  # 二进制的形式直接读取 后面就不用编码了
            except:  # 找不到文件就返回NOT FOUND
                response = 'HTTP/1.1 404  NOT FOUND\r\n'
                response += '\r\n'
                response += '-----not found---'
                new_socket.send(response.encode('utf-8'))
            else:  # 如果能打开文件就读取并发送
                html_contend = f.read()
                f.close()
                # 2.1 准备发送给浏览器的数据---header
                response = "HTTP/1.1 200 OK\r\n"
                response += '\r\n'  # 空行加body
                # response += '<b1>hehehe</b1>'#2.2 发送给浏览器的数据body
                new_socket.send(response.encode('utf-8'))
                new_socket.send(html_contend)  # 不能和response一起发过去 因为是二进制的
        else:#一下代码最好再写一个py文件 (解耦)
            #2.2 如果以.py结尾 呢么就认为是动态资源的请求
            header = "HTTP/1.1 200 OK\r\n"
            header += '\r\n'
            body = "hahahhahahhaha %s" % time.ctime()
            response = header+body
            #发送response给浏览器
            new_socket.send(response.encode('utf-8'))
        new_socket.close()

1---------------------------------

 简单的解耦(将web服务器和逻辑代码分开):


        # 2 返回http格式的数据 给浏览器
        # 2.1 如果请求的资源不是以.py结尾 那么就认为是静态资源(html/css/js/png jpg等)
        if not file_name.endswith(".py"):
            try:
                # 打开想要的文件
                f = open(file_name, 'rb')  # 二进制的形式直接读取 后面就不用编码了
            except:  # 找不到文件就返回NOT FOUND
                response = 'HTTP/1.1 404  NOT FOUND\r\n'
                response += '\r\n'
                response += '-----not found---'
                new_socket.send(response.encode('utf-8'))
            else:  # 如果能打开文件就读取并发送
                html_contend = f.read()
                f.close()
                # 2.1 准备发送给浏览器的数据---header
                response = "HTTP/1.1 200 OK\r\n"
                response += '\r\n'  # 空行加body
                # response += '<b1>hehehe</b1>'#2.2 发送给浏览器的数据body
                new_socket.send(response.encode('utf-8'))
                new_socket.send(html_contend)  # 不能和response一起发过去 因为是二进制的
        else:
            #2.2 如果以.py结尾 呢么就认为是动态资源的请求
            header = "HTTP/1.1 200 OK\r\n"
            header += '\r\n'
            body = mini_frame.application(file_name)
            response = header+body
            #发送response给浏览器
            new_socket.send(response.encode('utf-8'))

逻辑代码 mini_frame.py:

#逻辑处理代码
import time
def login():
    return "---login--welcome to our web   time %s" % time.ctime()
def register():
    return "---register--welcome to our web   time %s" % time.ctime()
def application(file_name):
    if file_name == "/login.py":
        return login()
    elif file_name == "/register.py":
        return register()
    else:
        return 'not found page'

浏览器请求的某个资源最终对应到你的框架里的某个函数 而不是对应服务器里面的某个功能

2---------------------------------

web服务器支持WSGI 

        else:
            #2.2 如果以.py结尾 呢么就认为是动态资源的请求
            env = dict()
            env['PATH_INFO'] = file_name#字典 'PATH_INFO':'/index.py'
            body = mini_frame.application(env,self.set_response_header())#传递一个字典和一个函数的引用
            header = "HTTP/1.1 %s\r\n" % self.status
            for temp in self.headers:
                header += '%s:%s\r\n' %(temp[0],temp[1])
            header += '\r\n'
            response = header+body
            #发送response给浏览器
            new_socket.send(response.encode('utf-8'))

        new_socket.close()
    def set_response_header(self,status,headers):
        self.status = status
        self.headers = [('server','mini_web v8.8')]
        self.headers += headers

简单模拟框架:

import time
def login():
    return "---login--welcome to our web   time %s" % time.ctime()
def register():
    return "---register--welcome to our web   time %s" % time.ctime()
def application(env,start_response):
    start_response('200 OK',[('Content-Type', 'text/html;charset=utf-8')])
    #start_response相当于是服务器里面的set_response_header函数 传递以上两个参数进去
    file_name = env['PATH_INFO']
    if file_name == "/login.py":
        return login()
    elif file_name == "/register.py":
        return register()
    else:
        return 'not found page'

浏览器访问服务器 服务器把请求扔给框架 框架打开模板 框架打开数据库里的请求 查询数据 把独到的模版的信息和数据库查出的信息进行替换 最终组成一个body 调用服务器里面的函数 设置header    通过return把body返回去 服务器把header和body组合返回给浏览器

------------------------------

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值