【web框架编写】05:14——框架:什么是web框架?为什么要有框架?
如果支持路径过多,需要写的单独的文件也会相应增多。
不同文件的application之间会有通用的工具。
不再把文件对应到路径中,而是整个网站全局只有一个如果,实现路由分发。
把“PATH_INFO”不对应到文件中,而是对应到application中的某一个部分上,由application进行调用。
只让web服务器加载一个文件,其中定义了一个application,建立路由信息(urls列表)进行映射,如果用户访问ctime.py执行ctime,如果访问sayhello.py执行sayhello。
目的是把多个文件压缩,只有一个入口Myweb.py,其中的application作为全局信息,能够被web服务器调用,在被调用的时候,用户请求信息放在env中,再去做映射。
Myweb.py中的application映射
如果使用框架,只在urls中加入映射。
框架:不用大规模改写,只在个别地方修改。
在web服务器程序中只提供一个py文件,里面的application映射多个py文件。
框架
符合WSGI协议的情况下, 文件中的application必须可以被调用(函数或者类),由于application函数中的代码不需要被改写,保持application代码不变,只修改属性,代码和行为不变,所以把它定义成一个类。
类中被实例的对象app需要被服务器调用,
一小时的视频看了好几遍,代码奉上:
web框架端(启动程序):
# coding:utf-8
import time
import sys
# 由于此文件是启动程序,所以需要从MyWebServer文件中导入
from MyWebServer import HTTPServer
sys.path.insert(1, './')
class Application(object):
"""框架的核心部分,也就是框架的主体程序,框架是通用的"""
# 构造函数接收路由信息,放入对象中保存
def __init__(self, urls):
# 设置路由信息
self.urls = urls
# 由于HTTPServer把application当成函数,所以需要__call__方法
def __call__(self, env, start_response):
# 字典的索引方式区别:get方法如果不存在不会退
# 出(不确定存在),[]方法会报异常(很确定存在)
# 后面的“/”表示如果没传默认根路径
path = env.get("PATH_INFO", "/")
# 路由分发:找到对应路径的对应程序,你去执行
for url, handler in self.urls:
# "/ctime", show_time()
if path == url:
# handler是对应路径的函数
# 调用__call__之后需要有返回值,
# 这个返回值从执行的函数中得到
# 一旦发现有比对值,直接返回,程序停止执行
return handler(env, start_response) # 把函数返回的信息直接返回
# 但别忘了后面的(env, start_response)两个参数
# 应该等到都遍历之后发现没有才返回错误信息
# 所以错误信息从此处开始404
status = "404 Not Nound"
headers = []
start_response(status, headers)
return "not found"
def show_ctime(env, start_response):
status = "200 OK"
headers = [
("Content-Type", "text/plain")
]
start_response(status, headers)
return time.ctime()
def say_hello(env, start_response):
status = "200 OK"
headers = [
("Conten-Type", "text/plain")
]
start_response(status, headers)
return "hello itcast"
if __name__ == "__main__":
urls = [
("/", show_ctime),
("/ctime", show_ctime),
("/sayhello", say_hello)
]
app = Application(urls)
http_server = HTTPServer(app) # 被明确导入了就可以直接用
http_server.bind(8080)
http_server.start()
# 需要使用的时候,只需要更改urls路由信息
web服务器端:
# coding:utf-8
import socket
import sys
import re
from multiprocessing import Process
# 定义一个常量用来接收客户端发起的文件请求地址
# 设置静态文件根目录
HTML_ROOT_DIR = "./html"
WSGI_PYTHON_DIR = "./wsgipython"
class HTTPServer(object):
def __init__(self, application):
"""构造函数,application指的是框架的app"""
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.app = application
def start(self):
self.server_socket.listen(128)
while True:
client_socket, client_address = self.server_socket.accept()
print("[%s, %s]用户连接上了" % client_address)
handle_client_process = Process(target=self.handle_client, args=(client_socket,))
handle_client_process.start()
client_socket.close()
def start_response(self, status, headers):
"""
status = "200 OK"
headers = [
("Content-Type", "text/plain")
]
star
"""
response_headers = "HTTP1.1 " + status + "\r\n"
for header in headers:
response_headers += "%s: %s\r\n" % header
self.response_headers = response_headers
def handle_client(self, client_socket):
# 获取客户端请求
request_data = client_socket.recv(1024)
print(request_data)
# 判断用户发来的请求
# 使用splitlines来切割不同行
request_lines = request_data.splitlines()
for line in request_lines:
print(line)
# GET / HTTP/1.1
request_start_line = request_lines[0]
file_name = re.match(r"\w+ +(/[^ ]*) ", request_start_line.decode("utf-8")).group(1)
method = re.match(r"(\w+) +/[^ ]* ", request_start_line.decode("utf-8")).group(1)
"""在对web服务器改写过程中,判断用户请求数据是动态资源还是静态资源通通不管"""
# time.py
env = {
"PATH_INFO": file_name,
"METHOD": method
}
# 所有以上信息都由app中的路由进行转发
response_body = self.app(env, self.start_response)
response = self.response_headers + "\r\n" + response_body
# 向客户端形响应数据
client_socket.send(bytes(response, "utf-8"))
# 关闭客户端连接
client_socket.close()
def bind(self, port):
self.server_socket.bind(("", port))
def main():
sys.path.insert(1, WSGI_PYTHON_DIR)
http_server = HTTPServer()
# http_server.set_port()
http_server.bind(8080)
http_server.start()
if __name__ == "__main__":
main()
网友评论