刷新页面会中断web socket吗_mini-web框架

237525ffb610303c5e2459a539e81454.png

1. 框架概述

web框架是一个为web服务器提供服务的应用程序,专门负责处理用户的动态资源请求.

静态资源: 资源的内容是固定不变的.

动态资源: 资源的内容是动态变化, 数据是从数据库获取的.

94b55ce3311cac207ae0af0f4686c2cd.png
静态 web 服务器 使用 tcp 传输数据
1. 导包 socket
2. 创建一个 socket 对象, socket.socket()
   端口复用(可选的)
3. 绑定 socket对象.bind((ip, 端口))
4. 监听 socket对象.listen()
5. 等待连接 socket对象.accept()---> 阻塞等待客户端连接,返回一个新的 socket 对象
6. 接收信息(请求报文)  recv
7. 发送信息(响应报文)  send
8. 关闭套接字  close()
------------------------------------------
web  服务器的工作流程
1. 在浏览器输入 URL 网址
2. 浏览器会访问 DNS 服务器, 做 DNS 解析, 将域名对应的 ip 进行返回
3. 和服务器建立连接(三次握手)
4. 发送请求报文
5. web 服务器接收浏览器发送报文, 解析报文, 判断请求的资源是静态资源还是动态资源  
6. 如果是静态资源, web 服务器自己处理,将内容返回
7. 如果是动态资源, 需要将请求交给 web 框架处理
8. web 框架根据 web 服务器发送的请求, 从模板库中读取需要的模版文件, 同时还需要中数据库中查询需要的数据, 将数据和模版文件进行整合,组成完整的数据
9. web 框架将整理后的数据和处理结果发送给 web 服务器
10. web 服务器根据 web 框架发送内容,组成响应报文,发送给浏览器
11. 浏览器将资源进行整合, 显示内容
---5 7 8 9 10 写代码实现---

2. 搭建框架

1. 找到之前书写的静态 web 服务器的代码, 作为 web 服务器使用

import socket
import threading

class HTTPWebServer(object):
    def __init__(self):
        # 1. 创建 socket
        server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 设置端口复用
        server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
        # 2. 绑定端口和 ip
        server_socket.bind(('', 8080))
        # 3. 设置监听
        server_socket.listen(128)
        self.server_socket = server_socket   # 将这个 socket 作为实例属性

    def __del__(self):  # 对象销毁的时候调用 close() 方法
        self.server_socket.close()

    @staticmethod
    def __handle_client_request(new_soc, client_ip_port):
        # 5. 接收信息(HTTP 请求报文)
        buf = new_soc.recv(4096)  # 一次性报文
        if buf:
            # 打印请求报文
            # print(buf.decode())
            buf = buf.decode()
            # 6. 发送信息(HTTP 响应报文)
            # 响应行  协议的版本  状态码  状态描述
            response_line = "HTTP/1.1 200 OKrn"
            # 响应头
            response_header = "Server:PYrnName:py40rn"
            # 空行(rn)
            # 响应体, 文件的内容, 读取文件,将文件的内容作为响应体发送
            file_name = buf.split(' ', 2)[1]
            print(f"请求的资源为{file_name}")
            # 访问的资源是 / ---> index.html
            if file_name == '/':
                file_name = '/index.html'

            try:
                with open('static' + file_name, 'rb') as f:  # rb, 读取出来的直接是 bytes
                    data = f.read()
            except FileNotFoundError:
                with open('static/error.html', 'rb') as f:
                    data = f.read()
                # 如果文件不存在, 修改响应行的状态码
                response_line = "HTTP/1.1 404 Not Foundrn"

            response = (response_line + response_header + 'rn').encode() + data
            new_soc.send(response)
        else:
            print(f"{client_ip_port} 断开连接...")
        # 7. 关闭连接
        new_soc.close()

    def start(self):
        # 4. 等待连接
        print('服务已启动,端口为 8080, 等待连接....')
        while True:
            new_socket, ip_port = self.server_socket.accept()
            print(f"{ip_port} 建立连接......")
            # 用户连接之后,创建一个线程
            sub_thread = threading.Thread(target=self.__handle_client_request, args=(new_socket, ip_port))
            sub_thread.start()

if __name__ == '__main__':
    # 创建对象
    web = HTTPWebServer()
    web.start()  # 启动服务器

2. 将 static 文件和 template 文件放到当天的代码目录中

3. 启动 web 服务器, 访问之前的静态页面, 能够正常访问

4. 修改 web 服务器的代码

3. 动态资源判断

判断一个资源是不是动态资源, 只需要判断资源是不是以 .html 结尾 字符串.endswith()

# 此时获取到文件的资源路径,需要判断是静态资源还是动态资源
if file_name.endswith('.html'):
    """动态资源, 交给框架处理"""
    # 思考,框架如何知道请求的是哪个页面 ---> 函数传参
    # 一般的方法, 将需要传递的数据组成字典传递
    # 好处: 可以传递多个数据
    env = {
        'filename': file_name,
        # 还可以传递其他参数,目前不需要
    }
    status, header, file_data = framework.handle_request(env)
    response_line = "HTTP/1.1 %srn" % status
    response_header = header
    data = file_data.encode()
else:
    """静态资源,web 服务器直接自己处理"""
    try:
        with open('static' + file_name, 'rb') as f:  # rb, 读取出来的直接是 bytes
            data = f.read()
    except FileNotFoundError:
        with open('static/error.html', 'rb') as f:
            data = f.read()
        # 如果文件不存在, 修改响应行的状态码
        response_line = "HTTP/1.1 404 Not Foundrn"

4. 处理客户端的动态资源请求

  1. 创建web框架程序
  2. 接收web服务器的动态资源请求
  3. 处理web服务器的动态资源请求并把处理结果返回给web服务器
  4. web服务器把处理结果组装成响应报文发送给浏览器

web框架程序(framework.py)代码:

"""miniweb框架,负责处理动态资源请求"""
import time

# 获取首页数据
def index():
    # 响应状态
    status = "200 OK";
    # 响应头
    response_header = [("Server", "PWS2.0")]
    # 处理后的数据
    data = time.ctime()

    return status, response_header, data

# 没有找到动态资源
def not_found():
    # 响应状态
    status = "404 Not Found";
    # 响应头
    response_header = [("Server", "PWS2.0")]
    # 处理后的数据
    data = "not found"

    return status, response_header, data

# 处理动态资源请求
def handle_request(env):
    # 获取动态请求资源路径
    request_path = env["filename"]
    print("接收到的动态资源请求:", request_path)

    if request_path == "/index.html":
        # 获取首页数据
        result = index()
        return result
    else:
        # 没有找到动态资源
        result = not_found()
        return result

5. 路由列表开发

路由: 请求的 URL 到到处理的函数之间的关系

5.1 在路由列表添加路由

# 定义路由列表, 在列表中保存所有的请求资源和处理函数的对应关系(Django)
route_list = [
    ('/index.html', index),  # 函数地址的引用, 不能加括号的
    ('/center.html', center)
]

def handle_request(env):
    """处理动态资源请求"""
    # 1. 获取web 服务器传递的参数
    file_name = env['filename']   # 通过字典的key 取值
    print(f'接收到要处理的动态资源是: {file_name}')
    # 遍历路由列表, 查找需要请求的资源是否在路由列表中
    for route in route_list:
        if file_name == route[0]:
            func = route[1]  # func 是一个函数
            return func()  # return route[1]()
    else:
        return not_found()

5.2 装饰器方式的添加路由

route_list = []

def my_route(filename):
    # 定义装饰器
    def decorator(fn):
        #  添加路由
        # route_list.append((filename, fn))

        def inner():
            return fn()

        route_list.append((filename, inner))
        return inner
    return decorator

@my_route('/index.html')
def index():   # 视图函数
    """专门用来处理首页数据的"""
    # 1. 从模板库读取 html 页面
    with open('template/index.html', 'r') as f:
        file_data = f.read()

6. 数据库准备

  1. 将提前给到大家的 stock_db.sql 复制到 Ubuntu 桌面中
  2. 登录 mysql 客户端 mysql -uroot -pmysql
  3. 创建数据库 create database stock_db charset=utf8;
  4. 使用这个数据库use stock_db
  5. 导入 SQL 语句 source ~/Desktop/stock_db.sql

7. index 页面处理

  1. 从数据库获取数据
  2. 使用这个数据进行模版替换
# 获取首页数据
@route("/index.html")
def index():
    # 响应状态
    status = "200 OK";
    # 响应头
    response_header = [("Server", "PWS2.0")]

    # 打开模板文件,读取数据
    with open("template/index.html", "r") as file:
        file_data = file.read()

    # 处理后的数据, 从数据库查询
    conn = pymysql.connect(host="localhost",
                           port=3306,
                           user="root",
                           password="mysql",
                           database="stock_db",
                           charset="utf8")

    # 获取游标
    cursor = conn.cursor()
    # 查询sql语句
    sql = "select * from info;"
    # 执行sql
    cursor.execute(sql)
    # 获取结果集
    result = cursor.fetchall()
    print(result)

    data = ""
    for row in result:
        data += '''<tr>
                    <td>%s</td>
                    <td>%s</td>
                    <td>%s</td>
                    <td>%s</td>
                    <td>%s</td>
                    <td>%s</td>
                    <td>%s</td>
                    <td>%s</td>
                    <td><input type="button" value="添加" id="toAdd" name="toAdd" systemidvaule="000007"></td>
                   </tr>''' % row

    # 替换模板文件中的模板遍历
    result = file_data.replace("{%content%}", data)

    return status, response_header, result

8. center 页面处理

前后端分离

  • 后端程序员提供数据接口
  • 前端程序员,在页面 发送 Ajax 请求,获取数据,解析数据,将数据显示到页面中

8.1 后端

# 个人中心数据接口开发
@route("/center_data.html")
def center_data():
    # 响应状态
    status = "200 OK";
    # 响应头
    response_header = [("Server", "PWS2.0"), ("Content-Type", "text/html;charset=utf-8")]
    conn = pymysql.connect(host="localhost",
                           port=3306,
                           user="root",
                           password="mysql",
                           database="stock_db",
                           charset="utf8")

    # 获取游标
    cursor = conn.cursor()
    # 查询sql语句
    sql = '''select i.code, i.short, i.chg, 
             i.turnover, i.price, i.highs, f.note_info 
             from info as i inner join focus as f on i.id = f.info_id;'''
    # 执行sql
    cursor.execute(sql)
    # 获取结果集
    result = cursor.fetchall()
    # 关闭游标
    cursor.close()
    # 关闭数据库连接
    conn.close()
    # 个人中心数据列表
    center_data_list = list()
    # 遍历每一行数据转成字典
    for row in result:
        # 创建空的字典
        center_dict = dict()
        center_dict["code"] = row[0]
        center_dict["short"] = row[1]
        center_dict["chg"] = row[2]
        center_dict["turnover"] = row[3]
        center_dict["price"] = str(row[4])
        center_dict["highs"] = str(row[5])
        center_dict["note_info"] = row[6]
        # 添加每个字典信息
        center_data_list.append(center_dict)

    # 把列表字典转成json字符串, 并在控制台显示
    json_str = json.dumps(center_data_list,ensure_ascii=False)
    print(json_str)
    return status, response_header, json_str

代码说明:

  • json.dumps函数把字典转成json字符串
  • 函数的第一个参数表示要把指定对象转成json字符串
  • 参数的第二个参数ensure_ascii=False表示不使用ascii编码,可以在控制台显示中文。
  • 响应头添加Content-Type表示指定数据的编码格式

8.2 前端

// 发送ajax请求获取个人中心页面数据
$.get("center_data.html", function (data) {

    var data_array = data;

    // 获取table标签对象
    var $table = $(".table")
    for(var i = 0; i < data_array.length; i++){
        // 获取每一条对象
        var center_obj = data_array[i];
        var row_html = '<tr>' +
            '<td>'+ center_obj.code +'</td>' +
            '<td>'+ center_obj.short +'</td>' +
            '<td>'+ center_obj.chg +'</td>' +
            '<td>'+ center_obj.turnover +'</td>' +
            '<td>'+ center_obj.price +'</td>' +
            '<td>'+ center_obj.highs +'</td>' +
            '<td>'+ center_obj.note_info +'</td>' +
            '<td><a type="button" class="btn btn-default btn-xs" href="/update/000007.html"> <span class="glyphicon glyphicon-star" aria-hidden="true"></span> 修改 </a></td><td><input type="button" value="删除" id="toDel" name="toDel" systemidvaule="000007"></td></tr>';
        // 为table标签添加每一行组装的html数据
        $table.append(row_html);
    }

}, "json");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值