python就业班 miniweb框架_python之MiniWeb框架

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

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

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

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

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

其接口原理就是实现application函数。

application函数格式如下:

defapplication(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模块

importsocketimportthreadingimportFreamWork#创建服务器类

classHttpServerSocket(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)defstart(self):whileTrue:#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()deftask(self, client_socket, ip_port):#7.接收数据

recv_data = client_socket.recv(1024).decode('utf-8')print(recv_data)if notrecv_data:print("客户端:%s下线了,端口号为:%s" %ip_port)return

#8.发送数据

#判断请求资源是否包含参数

#请求行格式:GET /index.html HTTP/1.1

recv_path = recv_data.split()[1]#print("第一次分割",recv_path)

#如果有参数则以?分割

if '?' inrecv_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()exceptException 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()defstart_response(self, status, response_header):

self.status=status

self.response_header=response_headerdef __del__(self):#当服务端程序结束时停止服务器服务

self.server_socket.close()defmain():

http_socket=HttpServerSocket()

http_socket.start()if __name__ == '__main__':

main()

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

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

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

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

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

2.MiniWeb框架代码实现:

importdbimportjson#定义一个路由表

router_table ={}#编写接口函数#environ参数用来接收请求资源路径#start_response参数用来接收传递过来的函数

defapplication(environ, start_response):

start_response('200 OK', [('Content-Type', 'text/html;charset=utf-8')])

func=errorif environ['PATH_INFO'] inrouter_table:

func= router_table[environ['PATH_INFO']]

body=func()returnbody#定义一个装饰器,用来实现路由表的自动维护

defrouter(url):defdecorator(func):def inner(*args, **kwargs):

body= func(*args, **kwargs)returnbody

router_table[url]=funcreturninnerreturndecorator#前后端不分离技术

@router('/index.html')defindex():

db_data=db.db_select()

with open('templates/index.html', 'r') as file:

body=file.read()

row_str= """

%s%s%s%s%s%s%s%s"""body_data= ''

for data indb_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)returnbody#前后端分离技术

@router('/center.html')defcenter():

with open('templates/center.html', 'r', encoding='utf-8') as file:

body=file.read()returnbody#编写接口函数

defcenter_data():

result=db.db_select_interface()#编写JSON数据

#JSON类型数据格式:[{"key":"value"},{"key":"value"},{"key":"value"}]

data =[]for i inresult:

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)returnjosn_data

@router('/update.html')defupdate():

with open('templates/update.html', 'r', encoding='utf-8') as file:

body=file.read()returnbodydeferror():return '

你的页面迷路了。。。

'

JSON的数据格式:

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

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

importpymysql#定义一个数据库连接函数

defdb_connect():

db= pymysql.connect(host='localhost', port=3306, user='root', password='mysql', database='stock_db', charset='utf8')#返回数据库连接对象

returndb#定义一个index页面查询数据的函数

defdb_select():

db=db_connect()

cur=db.cursor()

sql= '''select * from info;'''cur.execute(sql)

result=cur.fetchall()

cur.close()

db.close()returnresult#定义一个接口查询数据的函数

defdb_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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,让我来为您介绍一个简单的 Python Web 框架,它类似于 Django,名字叫做 MiniWebMiniWeb 实现了一个基本的 Web 框架功能,包括 URL 路由、请求处理、模板渲染等。下面是 MiniWeb 的代码示例: ```python # 引入必要的库 import re import os import sys import time import socket import select # 定义 MiniWeb 类 class MiniWeb: # 初始化方法 def __init__(self, host='', port=80): self.host = host self.port = port self.routes = [] # 添加路由方法 def route(self, pattern): def decorator(handler): self.routes.append((re.compile(pattern), handler)) return handler return decorator # 处理请求方法 def handle_request(self, request): # 提取请求方法和路径 method, path, _ = request.split(' ', 2) # 遍历路由规则 for pattern, handler in self.routes: # 如果路径匹配路由规则,则调用对应的处理函数 if pattern.match(path): return handler(request) # 如果没有匹配的路由规则,则返回 404 错误 return 'HTTP/1.1 404 Not Found\r\n\r\n' # 运行框架方法 def run(self): # 创建套接字并绑定地址 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.bind((self.host, self.port)) server_socket.listen(5) # 循环等待客户端连接 while True: # 使用 select 函数监听套接字 readable, _, _ = select.select([server_socket], [], [], 1) if readable: # 接受客户端连接并处理请求 client_socket, client_address = server_socket.accept() request = client_socket.recv(1024).decode() response = self.handle_request(request) client_socket.sendall(response.encode()) client_socket.close() # 定义路由处理函数 web = MiniWeb() @web.route('^/$') def index(request): return 'HTTP/1.1 200 OK\r\n\r\nHello, World!' @web.route('^/hello/(.*)$') def hello(request): name = request.split('/')[2] return f'HTTP/1.1 200 OK\r\n\r\nHello, {name}!' # 运行框架 if __name__ == '__main__': web.run() ``` 以上是 MiniWeb 的代码示例,您可以通过调用 `route` 方法来添加路由规则,然后编写对应的路由处理函数。当客户端发起请求时,MiniWeb 会根据路由规则来调用对应的路由处理函数,并返回处理结果。 当然,MiniWeb 还需要进一步的完善和优化,例如添加静态文件处理、错误处理、中间件等功能。但它足以作为一个简单的 Python Web 框架示例,帮助您更好地理解 Web 框架的实现原理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值