[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月前
|
安全 关系型数据库 测试技术
学习Python Web开发的安全测试需要具备哪些知识?
学习Python Web开发的安全测试需要具备哪些知识?
38 4
|
4天前
|
安全 前端开发 数据库
Python 语言结合 Flask 框架来实现一个基础的代购商品管理、用户下单等功能的简易系统
这是一个使用 Python 和 Flask 框架实现的简易代购系统示例,涵盖商品管理、用户注册登录、订单创建及查看等功能。通过 SQLAlchemy 进行数据库操作,支持添加商品、展示详情、库存管理等。用户可注册登录并下单,系统会检查库存并记录订单。此代码仅为参考,实际应用需进一步完善,如增强安全性、集成支付接口、优化界面等。
|
21天前
|
JSON 数据可视化 测试技术
python+requests接口自动化框架的实现
通过以上步骤,我们构建了一个基本的Python+Requests接口自动化测试框架。这个框架具有良好的扩展性,可以根据实际需求进行功能扩展和优化。它不仅能提高测试效率,还能保证接口的稳定性和可靠性,为软件质量提供有力保障。
52 7
|
18天前
|
分布式计算 大数据 数据处理
技术评测:MaxCompute MaxFrame——阿里云自研分布式计算框架的Python编程接口
随着大数据和人工智能技术的发展,数据处理的需求日益增长。阿里云推出的MaxCompute MaxFrame(简称“MaxFrame”)是一个专为Python开发者设计的分布式计算框架,它不仅支持Python编程接口,还能直接利用MaxCompute的云原生大数据计算资源和服务。本文将通过一系列最佳实践测评,探讨MaxFrame在分布式Pandas处理以及大语言模型数据处理场景中的表现,并分析其在实际工作中的应用潜力。
57 2
|
1月前
|
敏捷开发 测试技术 持续交付
自动化测试之美:从零开始搭建你的Python测试框架
在软件开发的马拉松赛道上,自动化测试是那个能让你保持节奏、避免跌宕起伏的神奇小助手。本文将带你走进自动化测试的世界,用Python这把钥匙,解锁高效、可靠的测试框架之门。你将学会如何步步为营,构建属于自己的测试庇护所,让代码质量成为晨跑时清新的空气,而不是雾霾中的忧虑。让我们一起摆脱手动测试的繁琐枷锁,拥抱自动化带来的自由吧!
|
2月前
|
开发框架 搜索推荐 数据可视化
Django框架适合开发哪种类型的Web应用程序?
Django 框架凭借其强大的功能、稳定性和可扩展性,几乎可以适应各种类型的 Web 应用程序开发需求。无论是简单的网站还是复杂的企业级系统,Django 都能提供可靠的支持,帮助开发者快速构建高质量的应用。同时,其活跃的社区和丰富的资源也为开发者在项目实施过程中提供了有力的保障。
|
2月前
|
开发框架 JavaScript 前端开发
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势。通过明确的类型定义,TypeScript 能够在编码阶段发现潜在错误,提高代码质量;支持组件的清晰定义与复用,增强代码的可维护性;与 React、Vue 等框架结合,提供更佳的开发体验;适用于大型项目,优化代码结构和性能。随着 Web 技术的发展,TypeScript 的应用前景广阔,将继续引领 Web 开发的新趋势。
45 2
|
2月前
|
开发者 Docker Python
从零开始:使用Docker容器化你的Python Web应用
从零开始:使用Docker容器化你的Python Web应用
55 1
|
2月前
|
JSON 前端开发 API
使用Python和Flask构建简易Web API
使用Python和Flask构建简易Web API
121 3
|
2月前
|
监控 安全 测试技术
如何在实际项目中应用Python Web开发的安全测试知识?
如何在实际项目中应用Python Web开发的安全测试知识?
36 4