[Python]mini-Web框架(一)

简介: [Python]mini-Web框架

image.png


前言

系列文章目录

[Python]目录

视频及资料和课件

链接:https://pan.baidu.com/s/1LCv_qyWslwB-MYw56fjbDg?pwd=1234

提取码:1234

1. web框架概述

1.1 web框架和web服务器的关系介绍

静态web服务器用于静态资源数据请求

动态资源请求使用web框架专门负责处理,这个web框架其实就是一个为web服务器提供服务的应用程序,简称web框架。

关系说明:

  1. web服务器接收浏览器发起的请求,如果是动态资源请求找web框架来处理
  2. web框架负责处理浏览器的动态资源请求,把处理的结果发生给web服务器
  3. web服务器再把响应结果发生给浏览器

1.2 静态资源

不需要经常变化的资源,这种资源web服务器可以提前准备好,比如: png/jpg/css/js等文件。

1.3 动态资源

和静态资源相反, 这种资源会经常变化,比如: 我们在京东浏览商品时经常会根据条件进行筛选,选择不同条件, 浏览的商品就不同,这种资源web服务器无法提前准备好,需要web框架来帮web服务器进行准备,在这里web服务器可以把.html的资源请求认为是动态资源请求交由web框架进行处理。

1.4 WSGI协议

它是web服务器和web框架之间进行协同工作的一个规则,WSGI协议规定web服务器把动态资源的请求信息传给web框架处理,web框架把处理好的结果返回给web服务器。

2. 框架程序开发

2.1 框架职责介绍

接收web服务器的动态资源请求,给web服务器提供处理动态资源请求的服务。

2.2 静态web服务器

import socket
import sys
import threading
# 定义web服务器类
class HttpWebServer(object):
    def __init__(self, port):
        # 创建tcp服务端套接字对象
        tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 设置端口号复用,程序退出端口号立即释放
        tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
        # 绑定端口号
        tcp_server_socket.bind(('', port))
        # 服务端套接字监听
        tcp_server_socket.listen(128)
        # 将tcp服务端套接字对象作为属性
        self.tcp_server_socket = tcp_server_socket
    # 启动web服务器进行工作
    def start(self):
        # 循环等待客户端的连接
        while True:
            # 等待接受客户端的连接请求
            new_socket, ip_port = self.tcp_server_socket.accept()
            print(ip_port)
            # 客户端与服务端建立连接后,创建子线程
            sub_thread = threading.Thread(target=self.handle_client_request, args=(new_socket,))
            # 设置守护主线程
            sub_thread.setDaemon(True)
            # 启动线程
            sub_thread.start()
    # 处理客户端的请求
    @staticmethod
    def handle_client_request(new_socket):
        # 接受客户端发送的数据
        # 由于浏览器一般不会发送大量的数据,所以一次接受的数据大小不用指定很大
        recv_client_data = new_socket.recv(4096)
        # 判断客户端是否处于连接转态
        if len(recv_client_data) == 0:
            new_socket.close()
            return
        # 对二进制数据进行解码
        recv_client_content = recv_client_data.decode('utf-8')
        print(recv_client_content)
        # 对字符串进行分割,分割两次,因为访问的资源路径在第二个位置
        request_list = recv_client_content.split(' ', maxsplit=2)
        # 获取请求资源地址
        request_path = request_list[1]
        print('请求的资源地址为:', request_path)
        # 如果请求的资源地址为 '/', 默认为首页index.html
        if request_path == '/':
            request_path = '/index.html'
        try:
            # 打开读取需要发送给客户端的文件
            with open('static' + request_path, 'rb') as f:
                # 读取文件数据
                file_data = f.read()
        except Exception as e:
            # 打开错误页面
            with open('static/error.html', 'rb') as f:
                # 读取文件数据
                file_data = f.read()
                # 将读取的数据封装为http格式的数据
                # 响应行
                response_line = 'HTTP/1.1 404 Not Found\r\n'
                # 响应头
                response_header = 'Server: PWS1.0\r\n'
                # 响应体
                response_body = file_data
                # 拼接为响应报文
                response_data = (response_line + response_header + '\r\n').encode('utf-8') + response_body
                # 发送数据给客户端
                new_socket.send(response_data)
        else:
            # 将读取的数据封装为http格式的数据
            # 响应行
            response_line = 'HTTP/1.1 200 OK\r\n'
            # 响应头
            response_header = 'Server: PWS1.0\r\n'
            # 响应体
            response_body = file_data
            # 拼接为响应报文
            response_data = (response_line + response_header + '\r\n').encode('utf-8') + response_body
            # 发送数据给客户端
            new_socket.send(response_data)
        finally:
            # 关闭与客户端的套接字
            new_socket.close()
# 程序入口函数
def main():
    print('服务器运行在9090端口...')
    # 创建web服务器对象
    # 服务器运行的端口为 9090
    web_server = HttpWebServer(9090)
    # 启动web服务器进行工作
    web_server.start()
# 判断是否为主模块
if __name__ == '__main__':
    main()

2.3 动态资源判断

根据请求资源路径的后缀名进行判断:

(1)如果请求资源路径的后缀名是.html则是动态资源请求, 让web框架程序进行处理。

(2)否则是静态资源请求,让web服务器程序进行处理。

静态web服务器:

# 如果请求的资源地址为 '/', 默认为首页index.html
        if request_path == '/':
            request_path = '/index.html'
        # 判断是动态资源请求还是静态资源请求, 后缀为.html的为动态资源请求
        if request_path.endswith('.html'):
            # 动态资源请求
            # 动态资源请求找web框架处理,需要把请求参数给web框架
            # 准备给web框架的参数信息
            # env 环境变量,WSGI协议规定给web框架的参数信息最好使用env命名
            env = {
                'request_path': request_path
                # 目前只传请求路径
                # 需要传递其他的信息,可以在字典中添加
            }
            # 使用框架处理动态资源请求
            # 1. web框架需要把处理结果返回web服务器
            # 2. web服务器负责把返回的结果封装成响应报文发送给浏览器
            # web框架需要返回 响应状态信息、响应头、响应体
            status, headers, response_body = framework.handle_request(env)
            # 将web框架处理的数据封装成响应报文
            # 响应行
            response_line = 'HTTP/1.1 %s\r\n' % status
            # 响应头
            response_header = ''
            for header in headers:
                # 对元组进行拆包,同时拼接进字符串
                response_header += '%s: %s\r\n' % header
            # 响应报文
            response_data = (response_line + response_header + '\r\n' + response_body).encode('utf-8')
            # 响应报文发送给浏览器
            new_socket.send(response_data)
            new_socket.close()
        else:
            # 静态资源请求
            # 执行原先静态web服务器的代码
            # 因为原先写的静态web服务器用于处理静态资源
            try:
                ...
            except Exception as e:
                ...
            else:
                ...
            finally:
                ...
import socket
import sys
import threading
# 导入web框架
import framework
# 定义web服务器类
class HttpWebServer(object):
    def __init__(self, port):
        # 创建tcp服务端套接字对象
        tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 设置端口号复用,程序退出端口号立即释放
        tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
        # 绑定端口号
        tcp_server_socket.bind(('', port))
        # 服务端套接字监听
        tcp_server_socket.listen(128)
        # 将tcp服务端套接字对象作为属性
        self.tcp_server_socket = tcp_server_socket
    # 启动web服务器进行工作
    def start(self):
        # 循环等待客户端的连接
        while True:
            # 等待接受客户端的连接请求
            new_socket, ip_port = self.tcp_server_socket.accept()
            print(ip_port)
            # 客户端与服务端建立连接后,创建子线程
            sub_thread = threading.Thread(target=self.handle_client_request, args=(new_socket,))
            # 设置守护主线程
            sub_thread.setDaemon(True)
            # 启动线程
            sub_thread.start()
    # 处理客户端的请求
    @staticmethod
    def handle_client_request(new_socket):
        # 接受客户端发送的数据
        # 由于浏览器一般不会发送大量的数据,所以一次接受的数据大小不用指定很大
        recv_client_data = new_socket.recv(4096)
        # 判断客户端是否处于连接转态
        if len(recv_client_data) == 0:
            new_socket.close()
            return
        # 对二进制数据进行解码
        recv_client_content = recv_client_data.decode('utf-8')
        print(recv_client_content)
        # 对字符串进行分割,分割两次,因为访问的资源路径在第二个位置
        request_list = recv_client_content.split(' ', maxsplit=2)
        # 获取请求资源地址
        request_path = request_list[1]
        print('请求的资源地址为:', request_path)
        # 如果请求的资源地址为 '/', 默认为首页index.html
        if request_path == '/':
            request_path = '/index.html'
        # 判断是动态资源请求还是静态资源请求, 后缀为.html的为动态资源请求
        if request_path.endswith('.html'):
            # 动态资源请求
            # 动态资源请求找web框架处理,需要把请求参数给web框架
            # 准备给web框架的参数信息
            # env 环境变量,WSGI协议规定给web框架的参数信息最好使用env命名
            env = {
                'request_path': request_path
                # 目前只传请求路径
                # 需要传递其他的信息,可以在字典中添加
            }
            # 使用框架处理动态资源请求
            # 1. web框架需要把处理结果返回web服务器
            # 2. web服务器负责把返回的结果封装成响应报文发送给浏览器
            # web框架需要返回 响应状态信息、响应头、响应体
            status, headers, response_body = framework.handle_request(env)
            # 将web框架处理的数据封装成响应报文
            # 响应行
            response_line = 'HTTP/1.1 %s\r\n' % status
            # 响应头
            response_header = ''
            for header in headers:
                # 对元组进行拆包,同时拼接进字符串
                response_header += '%s: %s\r\n' % header
            # 响应报文
            response_data = (response_line + response_header + '\r\n' + response_body).encode('utf-8')
            # 响应报文发送给浏览器
            new_socket.send(response_data)
            new_socket.close()
        else:
            # 静态资源请求
            # 执行原先静态web服务器的代码
            # 因为原先写的静态web服务器用于处理静态资源
            try:
                # 打开读取需要发送给客户端的文件
                with open('static' + request_path, 'rb') as f:
                    # 读取文件数据
                    file_data = f.read()
            except Exception as e:
                # 打开错误页面
                with open('static/error.html', 'rb') as f:
                    # 读取文件数据
                    file_data = f.read()
                    # 将读取的数据封装为http格式的数据
                    # 响应行
                    response_line = 'HTTP/1.1 404 Not Found\r\n'
                    # 响应头
                    response_header = 'Server: PWS1.0\r\n'
                    # 响应体
                    response_body = file_data
                    # 拼接为响应报文
                    response_data = (response_line + response_header + '\r\n').encode('utf-8') + response_body
                    # 发送数据给客户端
                    new_socket.send(response_data)
            else:
                # 将读取的数据封装为http格式的数据
                # 响应行
                response_line = 'HTTP/1.1 200 OK\r\n'
                # 响应头
                response_header = 'Server: PWS1.0\r\n'
                # 响应体
                response_body = file_data
                # 拼接为响应报文
                response_data = (response_line + response_header + '\r\n').encode('utf-8') + response_body
                # 发送数据给客户端
                new_socket.send(response_data)
            finally:
                # 关闭与客户端的套接字
                new_socket.close()
# 程序入口函数
def main():
    print('服务器运行在9090端口...')
    # 创建web服务器对象
    # 服务器运行的端口为 9090
    web_server = HttpWebServer(9090)
    # 启动web服务器进行工作
    web_server.start()
# 判断是否为主模块
if __name__ == '__main__':
    main()

web框架:

"""web框架用于处理动态资源请求"""
import time
def index():
    # 状态信息
    status = '200 OK'
    # 响应头信息
    # 这里使用列表套元组的方法存放信息,每个元组为一个信息
    response_header = [('Server', 'PWS/1.1')]
    # web框架成立后的数据
    # 获取当前时间
    date_now = time.ctime()
    # 返回信息
    # 返回的是元组
    return status, response_header, date_now
def not_found():
    # 状态信息
    status = '404 Not Found'
    # 响应头信息
    # 这里使用列表套元组的方法存放信息,每个元组为一个信息
    response_header = [('Server', 'PWS/1.1')]
    # web框架成立后的数据
    date_now = 'Not Found'
    # 返回信息
    # 返回的是元组
    return status, response_header, date_now
def handle_request(env):
    # 获取动态资源请求路径
    request_path = env['request_path']
    print('动态资源请求路径:', request_path)
    # 判断请求的动态资源路径,选中指定的函数处理对应的动态资源请求
    if request_path == '/index.html':
        # 返回处理数据
        return index()
    else:
        # 没有动态资源信息,返回404
        return not_found()

3. 模板替换功能开发

模板功能需要实现能够将数据库中查询出来的数据添加到需要返回给浏览器的页面中。

web框架代码:

# 1. 打开指定模板文件,读取模板文件中的数据
    with open('template/index.html', 'r') as f:
        f_data = f.read()
    # 2. 查询数据库,模板里面的模板变量({%content%})替换成从数据库中查询出来的数据
    # web框架处理后的数据
    # 获取当前时间,模拟从数据库中查询出来的数据
    date_now = time.ctime()
    response_body = f_data.replace('{%content%}', date_now)
    # 返回信息
    # 返回的是元组
    return status, response_header, response_body
"""web框架用于处理动态资源请求"""
import time
def index():
    # 状态信息
    status = '200 OK'
    # 响应头信息
    # 这里使用列表套元组的方法存放信息,每个元组为一个信息
    response_header = [('Server', 'PWS/1.1')]
    # 1. 打开指定模板文件,读取模板文件中的数据
    with open('template/index.html', 'r') as f:
        f_data = f.read()
    # 2. 查询数据库,模板里面的模板变量({%content%})替换成从数据库中查询出来的数据
    # web框架处理后的数据
    # 获取当前时间,模拟从数据库中查询出来的数据
    date_now = time.ctime()
    response_body = f_data.replace('{%content%}', date_now)
    # 返回信息
    # 返回的是元组
    return status, response_header, response_body
def not_found():
    # 状态信息
    status = '404 Not Found'
    # 响应头信息
    # 这里使用列表套元组的方法存放信息,每个元组为一个信息
    response_header = [('Server', 'PWS/1.1')]
    # web框架成立后的数据
    date_now = 'Not Found'
    # 返回信息
    # 返回的是元组
    return status, response_header, date_now
def handle_request(env):
    # 获取动态资源请求路径
    request_path = env['request_path']
    print('动态资源请求路径:', request_path)
    # 判断请求的动态资源路径,选中指定的函数处理对应的动态资源请求
    if request_path == '/index.html':
        # 返回处理数据
        return index()
    else:
        # 没有动态资源信息,返回404
        return not_found()


相关文章
|
2月前
|
JSON 监控 BI
拼多多批量下单工具,拼多多买家批量下单软件,低价下单python框架分享
使用Selenium实现自动化操作流程多线程订单处理提升效率
|
2月前
|
机器人 数据安全/隐私保护 Python
企业微信自动回复软件,企业微信自动回复机器人,python框架分享
企业微信机器人包含完整的消息处理流程,支持文本消息自动回复、事件处理、消息加密解密等功能
|
2月前
|
JSON 数据安全/隐私保护 数据格式
拼多多批量下单软件,拼多多无限账号下单软件,python框架仅供学习参考
完整的拼多多自动化下单框架,包含登录、搜索商品、获取商品列表、下单等功能。
|
2月前
|
存储 API 数据库
自动发短信的软件,批量自动群发短信,手机号电话号生成器【python框架】
这个短信群发系统包含以下核心功能: 随机手机号生成器(支持中国号码) 批量短信发送功能(使用Twilio API)
|
2月前
|
JSON 机器人 API
微信机器人自动回复插件,vx自动回复机器人脚本助手,python框架分享
这个微信机器人系统包含三个主要模块:主程序基于itchat实现微信消息监听和自动回复功能
|
1月前
|
API 数据安全/隐私保护 Python
拼多多批量上架软件, 电商一键上货发布工具,python电商框架分享
多线程批量上传架构,支持并发处理商品数据 完整的拼多多API签名和token管理机制
|
2月前
|
前端开发 数据安全/隐私保护 Python
虚拟物流单号生成器, 虚拟快递单号假物流信息, 虚拟快递单号在线生成【python框架】
这个虚拟物流单号生成系统包含以下功能:支持多种主流快递公司的单号生成
|
2月前
|
消息中间件 存储 API
抖音私信协议软件,抖音群发私信的工具,抖音自动私信插件【python框架】
这个框架包含配置管理、消息队列、API客户端和主程序四个主要模块。配置管理负责存储账号信息和设置
|
2月前
|
数据采集 API 调度
Python爬虫框架对比:Scrapy vs Requests在API调用中的应用
本文对比了 Python 中 Scrapy 与 Requests 两大爬虫框架在 API 调用中的差异,涵盖架构设计、调用模式、性能优化及适用场景,并提供实战建议,助力开发者根据项目需求选择合适工具。
|
2月前
|
API 数据安全/隐私保护 Python
贴吧私信自动群发神器,百度贴吧群发批量私信脚本插件,python框架分享
这个贴吧私信群发工具包含三个主要文件:主程序、配置文件和入口文件。主程序实现了登录

热门文章

最新文章

推荐镜像

更多