Web框架的引入
为什么会有web框架
有了上一篇内容,静态、动态web服务器的实现,已经掌握了客户端请求到服务器处理的机制。在动态资源处理中,根据请求 .py 导入模块应用,然后调用应用入口程序实现动态处理。但是在真实的项目中,肯定有很多应用(.py文件),按照这种处理机制(每个应用中都要写一个入口,设置状态码、headers)不符合架构设计原则,这一部分肯定是可以复用的,所用应用应该公用一个入口,这就引入一个概念web框架。
设计思路
- 把每个应用中入口 application(env,start_response) 提取到web服务器中,然后在入口中通过路由机制分发到各应用中处理。
代码如下:
- WebFramework.py
`
# coding:utf-8
import time
from MyWebServer import WebServer
HTML_ROOT_DIR = "./static"
class Application(object):
'''自定义通用的web框架'''
# 初始化路由信息
def __init__(self,urls):
self.urls = urls
# 匹配路由
def __call__(self, env, start_response):
path = env.get("PATH_INFO", "/")
# /static/index.html
if path.startswith("/static"):
file_name = path[7:]
# 打开文件,读取内容
try:
file = open(HTML_ROOT_DIR + file_name, "rb")
except IOError:
# 代表未找到路由信息,404错误
status = "404 Not Found"
headers = []
start_response(status, headers)
return "not found"
else:
file_data = file.read()
file.close()
status = "200 OK"
headers = []
start_response(status, headers)
return file_data.decode("utf-8")
for url,handler in self.urls:
if path == url:
return handler(env,start_response)
# 未匹配到
status = '404 Not Found'
headers = []
start_response(status,headers)
return 'not found'
def showtime(env,start_response):
status = '200 OK'
headers = [
('Content-Type', 'text/plain')
]
start_response(status, headers)
return str(time.time())
def sayhello(env,start_response):
status = '200 OK'
headers = [
('Content-Type','text/plain')
]
start_response(status,headers)
return 'say hello'
def helloworld(env,start_response):
status = '200 OK'
headers =[
('Content-Type','text/plain')
]
start_response(status,headers)
return 'hello world'
if __name__ == '__main__':
urls = [
('/', showtime),
('/sayhello',sayhello),
('/helloworld',helloworld)
]
app = Application(urls)
webServer = WebServer(app)
webServer.bind(8000)
webServer.start()
`
- MyWebServer.py
`
# coding:utf-8
import socket
import re
import sys
from multiprocessing import Process
HTML_ROOT_DIR = './static'
WSGI_PY = './wsgipy'
class WebServer(object):
'''
简单的webserver
'''
def __init__(self,application):
'''application:框架'''
self.sock_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.app = application
def start(self):
self.sock_server.listen(128)
while True:
sock_client, addr = self.sock_server.accept()
print('[%s,%s]用户已连接......' % addr)
handle_client_process = Process(target=self.handle_client, args=(sock_client,))
handle_client_process.start()
sock_client.close()
def start_response(self, status, headers):
"""
status = "200 OK"
headers = [
("Content-Type", "text/plain")
]
star
"""
resp_headers = 'HTTP/1.1 ' + status + '\r\n'
for header in headers:
resp_headers += '%s: %s\r\n' % header
self.resp_headers = resp_headers
def handle_client(self, sock_client):
'''处理客户端请求'''
recv_data = sock_client.recv(1024)
#print('请求数据:', recv_data)
req_lines = recv_data.splitlines()
#for line in req_lines:
# print(line)
req_start_line = req_lines[0]
#print(req_start_line.decode('utf-8'))
file_name = re.match(r"\w+ +(/[^ ]*) ", req_start_line.decode("utf-8")).group(1)
method = re.match(r"(\w+) +/[^ ]* ", req_start_line.decode("utf-8")).group(1)
env = {
"PATH_INFO": file_name,
"METHOD": method
}
response_body = self.app(env, self.start_response)
response = self.resp_headers + "\r\n" + response_body
# 向客户端返回响应数据
sock_client.send(bytes(response, "utf-8"))
# 关闭客户端连接
sock_client.close()
def bind(self, port):
self.sock_server.bind(('', port))
def main():
sys.path.insert(1,WSGI_PY)
webServer = WebServer()
webServer.bind(8000)
webServer.start()
if __name__ == '__main__':
main()
`
启动
入口实在WebFramework.py 中,直接启动该文件,客户端请求指定路径即可看到效果。但是对于大多框架都是通过命令行启动,我们不可能在程序中这样启动,而且对于webserver来说始终是不变得,变的是web框架,所以改造成命令行启动,代码如下:
- WebFramework.py
`
# coding:utf-8
import time
HTML_ROOT_DIR = "./static"
class Application(object):
'''自定义通用的web框架'''
# 初始化路由信息
def __init__(self,urls):
self.urls = urls
# 匹配路由
def __call__(self, env, start_response):
path = env.get("PATH_INFO", "/")
# /static/index.html
if path.startswith("/static"):
file_name = path[7:]
# 打开文件,读取内容
try:
file = open(HTML_ROOT_DIR + file_name, "rb")
except IOError:
# 代表未找到路由信息,404错误
status = "404 Not Found"
headers = []
start_response(status, headers)
return "not found"
else:
file_data = file.read()
file.close()
status = "200 OK"
headers = []
start_response(status, headers)
return file_data.decode("utf-8")
for url,handler in self.urls:
if path == url:
return handler(env,start_response)
# 未匹配到
status = '404 Not Found'
headers = []
start_response(status,headers)
return 'not found'
def showtime(env,start_response):
status = '200 OK'
headers = [
('Content-Type', 'text/plain')
]
start_response(status, headers)
return str(time.time())
def sayhello(env,start_response):
status = '200 OK'
headers = [
('Content-Type','text/plain')
]
start_response(status,headers)
return 'say hello'
def helloworld(env,start_response):
status = '200 OK'
headers =[
('Content-Type','text/plain')
]
start_response(status,headers)
return 'hello world'
urls = [
('/', showtime),
('/sayhello',sayhello),
('/helloworld',helloworld)
]
app = Application(urls)
# if __name__ == '__main__':
# urls = [
# ('/', showtime),
# ('/sayhello',sayhello),
# ('/helloworld',helloworld)
# ]
# app = Application(urls)
#
# webServer = WebServer(app)
# webServer.bind(8000)
# webServer.start()
`
- MyWebServer.py
`
# coding:utf-8
import socket
import re
import sys
from multiprocessing import Process
HTML_ROOT_DIR = './static'
WSGI_PY = './wsgipy'
class WebServer(object):
'''
简单的webserver
'''
def __init__(self,application):
'''application:框架'''
self.sock_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.app = application
def start(self):
self.sock_server.listen(128)
while True:
sock_client, addr = self.sock_server.accept()
print('[%s,%s]用户已连接......' % addr)
handle_client_process = Process(target=self.handle_client, args=(sock_client,))
handle_client_process.start()
sock_client.close()
def start_response(self, status, headers):
"""
status = "200 OK"
headers = [
("Content-Type", "text/plain")
]
star
"""
resp_headers = 'HTTP/1.1 ' + status + '\r\n'
for header in headers:
resp_headers += '%s: %s\r\n' % header
self.resp_headers = resp_headers
def handle_client(self, sock_client):
'''处理客户端请求'''
recv_data = sock_client.recv(1024)
#print('请求数据:', recv_data)
req_lines = recv_data.splitlines()
#for line in req_lines:
# print(line)
req_start_line = req_lines[0]
#print(req_start_line.decode('utf-8'))
file_name = re.match(r"\w+ +(/[^ ]*) ", req_start_line.decode("utf-8")).group(1)
method = re.match(r"(\w+) +/[^ ]* ", req_start_line.decode("utf-8")).group(1)
env = {
"PATH_INFO": file_name,
"METHOD": method
}
response_body = self.app(env, self.start_response)
response = self.resp_headers + "\r\n" + response_body
# 向客户端返回响应数据
sock_client.send(bytes(response, "utf-8"))
# 关闭客户端连接
sock_client.close()
def bind(self, port):
self.sock_server.bind(('', port))
def main():
sys.path.insert(1,WSGI_PY)
if len(sys.argv) < 2:
sys.exit("python MyWebServer.py Module:app")
module_name, app_name = sys.argv[1].split(':')
m = __import__(module_name)
app = getattr(m,app_name)
webServer = WebServer(app)
webServer.bind(8000)
webServer.start()
if __name__ == '__main__':
main()
`
调用方式
在命令行中,执行如下命令即可启动webserver服务,模块名称:应用框架名, 其中这里的app指的是WebFramework.py中Application类的实例,其实也就是应用框架的实例。后续自定义框架的时候,直接调用即可。
`
python MyWebServer.py WebFramework:app
`
代码已上传到github:python 小程序
Web框架的引入的更多相关文章
- 09 基于模块wsgiref版web框架
09 基于模块wsgiref版web框架 模块引入 真实开发中的python web程序,一般会分为两部分: 服务器程序:负责对socket服务器进行封装,并在请求到来时,对请求的各种数据 ...
- web框架引入
1. web请求的本质就是一个socket. 2.http:一次请求,一次响应,断开链接.如下程序:必须先运行服务器端,然后客户端才能去连接.所有web框架的本质就是如下: import socket ...
- Python之Web框架Django
Python之Web框架: Django 一. Django Django是一个卓越的新一代Web框架 Django的处理流程 1. 下载地址 Python 下载地址:https://www.pyt ...
- Spring 5 新特性:函数式Web框架
举例 我们先从示例应用程序的一些摘录开始.下面是暴露Person对象的响应信息库.很类似于传统的,非响应信息库,只不过它返回Flux<Person>而传统的返回List<Person ...
- 关于Python的web框架
uliwebhttp://git.oschina.net/limodou/uliweb uliweb 吸取了其他框架的经验,集成了orm.总的来说一般.这个安装后有个exe文件,命令行工具.不绿色.个 ...
- python_way day17 html-day3 前端插件(fontawsome,easyui,bootstrap,jqueryui,bxslider,jquerylazyload),web框架
python_way day17 一.模板插件 图标的插件 fontawsome: 后台管理: easyui jqueryui 很多网站都会用: bootstrap :引入jQuery:(2.x,1. ...
- Day17 表单验证、滚动菜单、WEB框架
一.表单验证的两种实现方式 1.DOM绑定 <!DOCTYPE html> <html lang="en"> <head> <meta c ...
- Python开发【第二十二篇】:Web框架之Django【进阶】
Python开发[第二十二篇]:Web框架之Django[进阶] 猛击这里:http://www.cnblogs.com/wupeiqi/articles/5246483.html 博客园 首页 ...
- python运维开发(十七)----jQuery续(示例)web框架django
内容目录: jQuery示例 前端插件 web框架 Django框架 jQuery示例 dom事件绑定,dom绑定在form表单提交按钮地方都会绑定一个onclick事件,所有查看网站的人都能看到代码 ...
随机推荐
- DB2中查询前十数据的sql
select * from A fetch first 10 rows only
- FormData上传文件同时附带其他参数
前端js代码: function fileSubmit() { var formData = new FormData(); formData.append(].files[]); var type ...
- zabbix日志监控
一般情况下,日志最先反映出应用当前的问题,在海量日志里面找到我们异常记录,例如监控系统日志.nginx.Apache.业务日志,然后记录下来,并且根据情况报警. 1.日志监控项介绍 最主要的是监控日志 ...
- 使用uncompyle2直接反编译python字节码文件pyo/pyc
update:在Mac OS X版的September 10, 2014版(5.0.9-1)中发现安装目录中的src.zip已更换位置至WingIDE.app/Contents/Resources/b ...
- debounce 防抖动函数
http://lodash.think2011.net/debounce _.debounce(func, [wait=0], [options]) 创建一个防抖动函数. 该函数会在 wait 毫秒后 ...
- 数据库设计--数据流图(DFD)
1.数据流图的定义 数据流图(DFD)是结构化分析方法中使用的工具,它以图形的方式描绘数据在系统中流动和处理的过程, 因为它仅仅反映系统必须完毕的逻辑功能.所以它是一种功能模型. 在结构化开发方法中. ...
- rk3288 LED上加入heartbeat功能
平台:瑞芯的rk3288 作者:fulinux *****本文同意转载.只是请注明出处:http://blog.csdn.net/fulinus**** 1.硬件环境 随意选取一个GPIO引脚作为he ...
- Hadoop eclipse插件使用过程中出现的问题
http://download.csdn.net/detail/java2000_wl/4326323 转自http://www.ithao123.cn/content-945210.html 由于h ...
- 应用沙盒(Application Sandbox)
一.应用沙盒目录 应用沙盒包含多个目录: 1.应用程序包:(application bundle):包含所有的资源文件和可执行文件,并且是只读目录. 2.Library/Preferences/:存放 ...
- msyql5.5修改配置文件开启慢查询日志
修改/etc/my.cnf文件 在[mysqld]下面修改或添加配置(在别处不起作用) slow_query_log = on slow_query_log_file = /usr/local/mys ...