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事件,所有查看网站的人都能看到代码 ...
随机推荐
- 常见java异常
1. java.lang.NullPointerException(空指针异常) 调用了未经初始化的对象或者是不存在的对象 经常出现在创建图片,调用数组这些操作中,比如图片未经初始化,或者图片创建时 ...
- 10 种机器学习算法的要点(附 Python)(转载)
一.前言 谷歌董事长施密特曾说过:虽然谷歌的无人驾驶汽车和机器人受到了许多媒体关注,但是这家公司真正的未来在于机器学习,一种让计算机更聪明.更个性化的技术 也许我们生活在人类历史上最关键的时期:从使用 ...
- Android 比ListView更好用强大的RecyclerView库:RecyclerViewLibrary
RecyclerViewLibrary A RecyclerView libirary ,has some support, like headerAdapter/TreeAdapter,and Pu ...
- UI自动化测试篇 :Selenium2(Webdriver)&TestNG自动化测试环境搭建
最开始学习UI自动化,用的工具是QTP10,用起来确实比较容易上手,自学了没多久,大家都说QTP过时了.这么好用的的工具怎么一下子就过时了呢?因为它的“笨重”,因为它作为商业软件带来的巨大使用成本,还 ...
- 网络编程readn、writen和readline函数的编写
readn 在Linux中,read的声明为: ssize_t read(int fd, void *buf, size_t count); 它的返回值有以下情形: 1.大于0,代表成功读取的字节 ...
- HTML 5 音频Audio
在HTML5标准网页里面,我们能够运用audio标签来完毕我们对声音的调用及播放. 下面是最常常见到的运用HTML5三种基本格式: 1.最少的代码 <audio src="song.o ...
- Jmeter启动报注册表警告
启动Jmeter后,控制台出现如下的警告: 主要出现的原因是: java.util.prefs.WindowsPreferences需要保存信息到HKEY_LOCAL_MACHINE\Software ...
- 拒绝IP登陆
tail -n 30 /var/log/messages 发现很多IP尝试登陆,直接封禁. 解决方案:1. vi /etc/hosts.allow 添加 sshd:143.63.182.238 [注意 ...
- 【BIEE】03_BIEE数据源配置
声明:此时说的是Oracle数据源配置 BIEE数据源配置有两种方法 ①直接使用字符串连接 ②将tnsnames.ora文件覆盖到obiee目录下 直接使用字符串 直接使用字符串连接很简单 首先打开资 ...
- Mybatis 存在多个日志时设置日志
mybatis默认使用log4j,当有self4j这个日志jar包存在时会无法打印sql,请移除或者在工程启动时显示设置mybatis使用的日志类 log4j.logger.org.apache.ib ...