搭建一个简单的Web框架
概述
本文通过使用 wsgiref 模块搭建一个简单的WEB框架,旨在了解框架的基本运行原理
基本的接受数据跟发送数据
from wsgiref.simple_server import make_server
def application(environ, start_response):
print(environ) # 客户端返回给服务器的内容已经被打包好放在了这个environ字典里面了
start_response('200 OK', [('Content-Type', 'text/html')])
return [b'<h1>Hello, Web!</h1>']
httpd = make_server('', 8080, application)
print('Serving HTTP ON PORT 8080...')
# 开始监听HTTP请求
httpd.serve_forever() # ①
"""
python内置了WSGI服务器wsgiref相当于一个服务软件,作用与apache和nginx等相似,设置好了HTTP请求
程序启动后会在①处阻塞住等待客户端(浏览器)的请求,当有请求后会执行application方法,
在application方法中,存放所有的业务逻辑
environ是一个字典,将所有的来自客户端的HTTP请求信息封装成一个字典,需要什么直接去取就可以了,
start_response()是一个发送http响应的函数,执行该函数一次,就是发送了HTTP响应的Header,Header只能发送一次,
也就是说该方法只能调用一次,方法接收两个参数,一个是HTTP响应码,一个是一组list表示HTTP的Header,每一个Header用
一个包含两个字符串(键跟值)的元组表示
在方法的最后会返回一个字符串列表,该内容就是HTTP响应的Body部分,如果太长可以通过文件读取的方式返回,注意,必须是字节类型!!
"""
通过URL跳转到对应的页面
上面通过wsgiref模块总算是能够跟浏览器"说上话了",但是如何做到输入不同的URL来跳转到不同的页面呢,其实只需要获取 environ 字典中的 "PATH_INFO",这里面就存有这次http请求的URL,我们只需要拿到该URL,然后根据不同的URL返回不听的页面即可
# 业务升级,通过URL实现跳转到相关的页面
from wsgiref.simple_server import make_server
# 处理URL为 /xin 的请求
def foo1():
f = open("index1.html")
data = f.read()
f.close()
return data
# 处理URL为 /scarlett 的请求
def foo2():
f = f = open("index2,html")
data = f.read()
f.close()
return data
def application(environ, start_response):
print(environ["PATH_INFO"]) # 该键对应的值就是服务器名后面的路径,比如127.0.0.1:8080/xin,拿到的就是/xin
start_response('200 OK', [('Content-Type', 'text/html')])
path = environ["PATH_INFO"] # 获取这次http请求的URL
# 根据URL判断返回的页面
if path == "/xin":
return [foo1()]
elif path == "/scarlett":
return [foo2()]
else:
return [b'<h1>Hello, Web!</h1>']
httpd = make_server('', 8080, application)
print('Serving HTTP ON PORT 8080...')
# 开始监听HTTP请求
httpd.serve_forever() # 等待浏览器返回数据
通过一个单独的函数处理URL
上面已经解决了根据不同的URL跳转到不同的页面,但是是通过 if elif 去判断每个URL的,这样写的弊端算是很明显的,就是如果这里有100个不同的URL,岂不是要写100个 if elif?这样做的效率显然是很低的,那么该怎样解决呢?
这里提出了一种办法,就是专门拿出一个函数去处理URL请求,也就是路由映射
from wsgiref.simple_server import make_server
def login(req):
pass
def register(req):
pass
# 路由函数,解决URL过多问题
# 在这里面定义一个列表,值由是一个个元组,将URL路径对相应的处理函数对应了起来
def router():
urlpatterns = [
('/login', login),
('/register', register),
]
return urlpatterns
def application(environ, start_response):
print(environ["PATH_INFO"]) # 该键对应的值就是服务器名后面的路径,比如127.0.0.1:8080/xin,拿到的就是/xin
start_response('200 OK', [('Content-Type', 'text/html')])
path = environ["PATH_INFO"] # 获取到这次http请求的URL路径
urlpattern = router()
# 循环遍历里面的参数跟PATH_INFO匹配
func = None
for item in urlpattern:
if item[0] == path:
func = item[1]
break # 找到后跳出,不在循环后面的内容
return [func(environ)] # 将客户端HTTP请求信息传进去
httpd = make_server('', 8080, application)
print('Serving HTTP ON PORT 8080...')
# 开始监听HTTP请求
httpd.serve_forever()
在前端显示后端传入的变量
有的时候,想把后端产生的数据以变量的形式发送给前端,但是python的变量在html中显然是不好使的,那么怎样去解决这个矛盾呢?
这里我们可以定义一套语法规则,比如将html页面的 # #之间的东西替换成要显示的python变量就可以了
html页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>show time</title>
</head>
<body>
<h1>现在是:#times#</h1>
</body>
</html>
上面的 #times#中的times是个变量,它记录先当前的时刻,但是这样写最后在页面显示的护额的一对不会是当前时间,仍会是#times#
但是在把html页面返回给浏览器的之前可以先进行处理,就是把#times#用变量替换掉,那这时候显示的就是当前时间而不是#times#了
python页面
from wsgiref.simple_server import make_server
def show_time(req):
print(req)
import time
# 获取当前的时间
times = time.ctime()
# 将要显示的页面打开
f = open("show_time.html", "rb")
data = f.read()
data = data.decode("utf8")
# 替换掉里面的变量内容,也就是将# #之间的变量用相应的值替换掉
data = data.replace("#times#", str(times))
return data.encode("utf8")
# 路由函数,解决URL过多问题
def router():
urlpatterns = [
('/show_time', show_time),
]
return urlpatterns
def application(environ, start_response):
print(environ["PATH_INFO"]) # 该键对应的值就是服务器名后面的路径,比如127.0.0.1:8080/xin,拿到的就是/xin
start_response('200 OK', [('Content-Type', 'text/html')])
path = environ["PATH_INFO"]
urlpattern = router()
# 循环遍历里面的参数跟PATH_INFO匹配
func = None
for item in urlpattern:
if item[0] == path:
func = item[1]
break # 找到后跳出,不在循环后面的内容
if func:
return [func(environ)] # 将客户端HTTP请求信息传进去
else:
return [b'<h1>404</h1>']
httpd = make_server('', 8080, application)
print('Serving HTTP ON PORT 8080...')
# 开始监听HTTP请求
httpd.serve_forever()

浙公网安备 33010602011771号