python之MiniWeb框架,,以往,我们多完成的是


以往,我们多完成的是静态web服务器,主要处理的都是一些已经‘写死’的数据,那么今天,我们来学习一下动态数据的处理。

说到动态数据,我们就需要了解一个东西,那就是web框架。

所谓web框架简单地说就是用来处理数据或模板的一个py程序。

那么接下,我就简单的给大家简述一下一个浏览器访问动态数据的整体流程。

WSGI服务器网管接口(Web Server Gateway Interface)是为python语言定义的一种服务器与框架进行通信的简单接口,

其接口原理就是实现application函数。
application函数格式如下:

def application(environ, func):    start_response(‘200 OK‘, [(‘Content-Type‘, ‘text/html;charset=utf-8‘)])    return ‘Hello MiniWeb‘

函数的第一个参数environ类型是一个字典,用来接收封装到字典内的请求资源路径。

函数的第二个参数func类型是一个函数,用来接收调用时传递的函数引用。

首先,我们先看一张图片

技术图片

这张图片完美的阐述了从浏览器到服务器到web框架的应用。

接下来我将给大家进行简单的阐述:

首先,大家需要明确一点本次开发中以.html后缀的文件为动态资源,其余均为静态资源

1.浏览器发送HTTP请求报文给服务器,

2.服务器根据HTTP请求报文的请求路径进行判断,

如果请求的是静态资源,那么服务器直接将静态资源的数据读出来然后拼接成HTTP响应报文返回给浏览器;

如果请求的是动态资源,那么服务器会将动态资源请求发送给web框架。

3.web框架接收到服务器转发的请求后,先对请求进行判断,

如果是请求模版那么web框架将会去模版中查找请求的模板,如果查询到请求的模板那就把模板数据返回给web服务器,再有服务器返回给浏览器,

如果请求的是数据那么web框架将会去数据库中进行操作,将查询等操作的数据或返回值,返回给web服务器,再有服务器返回给浏览器。

至此一个整体流程就阐述完毕了。

1.web服务器代码实现:

# 1.导入socket模块import socketimport threadingimport FreamWork# 创建服务器类class HttpServerSocket(object):    # 给服务器类的对象设置属性    def __init__(self):        # 2.创建Socket对象        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)        # 3.设置端口复用        self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)        # 4.绑定端口        self.server_socket.bind((‘‘, 8000))        # 5.设置监听        self.server_socket.listen(128)    def start(self):        while True:            # 6.等待客户端连接            client_socket, ip_port = self.server_socket.accept()            # gevent.spawn(self.task, client_socket, ip_port)            print("上线了", ip_port)            threading.Thread(target=self.task, args=(client_socket, ip_port), daemon=True).start()    def task(self, client_socket, ip_port):        # 7.接收数据        recv_data = client_socket.recv(1024).decode(‘utf-8‘)        print(recv_data)        if not recv_data:            print("客户端:%s下线了,端口号为:%s" % ip_port)            return        # 8.发送数据        # 判断请求资源是否包含参数        # 请求行格式:GET /index.html HTTP/1.1        recv_path = recv_data.split()[1]        # print("第一次分割",recv_path)        # 如果有参数则以?分割        if ‘?‘ in recv_path:            real_recv_path = recv_path.split(‘?‘)[0]            # print("?分割",real_recv_path)        else:            # 如果没有参数,则保持请求路径不变            real_recv_path = recv_path            # print("无?分割",real_recv_path)        # 设置没指定资源路径,默认返回index.html        if real_recv_path == ‘/‘:            real_recv_path = ‘/index.html‘        # 判断请求资源是静态资源还是动态资源        if real_recv_path.endswith(‘.html‘):            env = {‘PATH_INFO‘: real_recv_path}            # 调用框架中的application函数            response_body = FreamWork.application(env, self.start_response)            response_line = ‘HTTP/1.1 %s\r\n‘ % self.status            response_header = ‘Server: PWS/1.0\r\n‘            # self.response_header 接收的是列表中保存的元组需要进行解包处理            response_header += ‘%s :%s\r\n‘ % self.response_header[0]            send_data = (response_line + response_header + ‘\r\n‘ + response_body).encode(‘utf8‘)            client_socket.send(send_data)            client_socket.close()        else:            # 判断请求的资源路径是否存在            try:                with open(f"static{real_recv_path}", "rb") as file:                    response_body = file.read()            except  Exception as e:                # 如果不存在则返回404                response_line = ‘HTTP/1.1 404 NOT FOUND\r\n‘                response_header = ‘Server: PWS/1.0\r\n‘                response_body = ‘sorry nor found page!\r\n‘.capitalize()                send_data = (response_line + response_header + ‘\r\n‘ + response_body).encode(‘utf-8‘)                client_socket.send(send_data)            else:                # 如果存在则换回请求的页面信息                response_line = ‘HTTP/1.1 200 OK\r\n‘                response_header = ‘Server: PWS/1.0\r\n‘                send_data = (response_line + response_header + ‘\r\n‘).encode(‘utf-8‘) + response_body                client_socket.send(send_data)            finally:                # 断开与客户端连接                client_socket.close()    def start_response(self, status, response_header):        self.status = status        self.response_header = response_header    def __del__(self):        # 当服务端程序结束时停止服务器服务        self.server_socket.close()def main():    http_socket = HttpServerSocket()    http_socket.start()if __name__ == ‘__main__‘:    main()

核心代码(代码段中颜色为红色并加粗的代码)解读:

1.通过分解后的请求资源路径的后缀判断请求的是否是html页面,如果是则认为请求的是动态资源;

2.将动态资源路径封装到一个字典中,并将字典和函数的引用传递给application函数,

3.web框架(application函数)根据传递的资源路径去模板中查找是否含有请求的模板,如果有则读取模版数据并返回;

4.接收到web框架(application函数)返回的数据,并拼接HTTP响应报文,然后通过浏览器套接字将HTTP响应报文发送给浏览器,最后关闭与浏览器连接。

2.MiniWeb框架代码实现:

import dbimport json# 定义一个路由表router_table = {}# 编写接口函数# environ参数用来接收请求资源路径# start_response参数用来接收传递过来的函数def application(environ, start_response):    start_response(‘200 OK‘, [(‘Content-Type‘, ‘text/html;charset=utf-8‘)])    func = error    if environ[‘PATH_INFO‘] in router_table:        func = router_table[environ[‘PATH_INFO‘]]    body = func()    return body# 定义一个装饰器,用来实现路由表的自动维护def router(url):    def decorator(func):        def inner(*args, **kwargs):            body = func(*args, **kwargs)            return body        router_table[url] = func        return inner    return decorator# 前后端不分离技术@router(‘/index.html‘)def index():    db_data = db.db_select()    with open(‘templates/index.html‘, ‘r‘) as file:        body = file.read()    row_str = """            <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="%s">                </td>            </tr>    """    body_data = ‘‘    for data in db_data:        body_data += row_str % (data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[1])    body = body.replace(‘{%content%}‘, body_data)    return body# 前后端分离技术@router(‘/center.html‘)def center():    with open(‘templates/center.html‘, ‘r‘, encoding=‘utf-8‘) as file:        body = file.read()    return body# 编写接口函数def center_data():    result = db.db_select_interface()    # 编写JSON数据    # JSON类型数据格式:[{"key":"value"},{"key":"value"},{"key":"value"}]    data = []    for i in result:        dd = {}        dd[‘code‘] = i[0]        dd[‘short‘] = i[1]        dd[‘chg‘] = i[2]        dd[‘turnover‘] = i[3]        dd[‘price‘] = i[4]        dd[‘highs‘] = i[5]        dd[‘info‘] = i[6]        data.append(dd)    # 将数据装换成JSON类型数据    # data:要转换的字符串    # ensure_ascii设置是否用ASCII码解析,False为否,True为是    josn_data = json.dumps(data,ensure_ascii=False)    return josn_data@router(‘/update.html‘)def update():    with open(‘templates/update.html‘, ‘r‘, encoding=‘utf-8‘) as file:        body = file.read()    return bodydef error():    return ‘<h1>你的页面迷路了。。。</h1>‘

JSON的数据格式:

[{"key":"value"},{"key":"value"},{"key":"value"}]

3.数据库操作文件代码实现:

import pymysql# 定义一个数据库连接函数def db_connect():    db = pymysql.connect(host=‘localhost‘, port=3306, user=‘root‘, password=‘mysql‘, database=‘stock_db‘, charset=‘utf8‘)    # 返回数据库连接对象    return db# 定义一个index页面查询数据的函数def db_select():    db = db_connect()    cur = db.cursor()    sql = ‘‘‘    select * from info;    ‘‘‘    cur.execute(sql)    result = cur.fetchall()    cur.close()    db.close()    return result# 定义一个接口查询数据的函数def db_select_interface():    db = db_connect()    cur = db.cursor()    sql = ‘‘‘select i.code, i.short, i.chg, i.turnover,i.price, i.highs, f.note_info from info i inner join focus f on i.id = f.info_id ‘‘‘    cur.execute(sql)    result = cur.fetchall()    cur.close()    db.close()    return result

python之MiniWeb框架

评论关闭