为什么会有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框架的引入的更多相关文章

  1. 09 基于模块wsgiref版web框架

    09 基于模块wsgiref版web框架 模块引入 真实开发中的python web程序,一般会分为两部分:       服务器程序:负责对socket服务器进行封装,并在请求到来时,对请求的各种数据 ...

  2. web框架引入

    1. web请求的本质就是一个socket. 2.http:一次请求,一次响应,断开链接.如下程序:必须先运行服务器端,然后客户端才能去连接.所有web框架的本质就是如下: import socket ...

  3. Python之Web框架Django

    Python之Web框架: Django 一. Django Django是一个卓越的新一代Web框架 Django的处理流程 1. 下载地址  Python 下载地址:https://www.pyt ...

  4. Spring 5 新特性:函数式Web框架

    举例 我们先从示例应用程序的一些摘录开始.下面是暴露Person对象的响应信息库.很类似于传统的,非响应信息库,只不过它返回Flux<Person>而传统的返回List<Person ...

  5. 关于Python的web框架

    uliwebhttp://git.oschina.net/limodou/uliweb uliweb 吸取了其他框架的经验,集成了orm.总的来说一般.这个安装后有个exe文件,命令行工具.不绿色.个 ...

  6. python_way day17 html-day3 前端插件(fontawsome,easyui,bootstrap,jqueryui,bxslider,jquerylazyload),web框架

    python_way day17 一.模板插件 图标的插件 fontawsome: 后台管理: easyui jqueryui 很多网站都会用: bootstrap :引入jQuery:(2.x,1. ...

  7. Day17 表单验证、滚动菜单、WEB框架

    一.表单验证的两种实现方式 1.DOM绑定 <!DOCTYPE html> <html lang="en"> <head> <meta c ...

  8. Python开发【第二十二篇】:Web框架之Django【进阶】

    Python开发[第二十二篇]:Web框架之Django[进阶]   猛击这里:http://www.cnblogs.com/wupeiqi/articles/5246483.html 博客园 首页 ...

  9. python运维开发(十七)----jQuery续(示例)web框架django

    内容目录: jQuery示例 前端插件 web框架 Django框架 jQuery示例 dom事件绑定,dom绑定在form表单提交按钮地方都会绑定一个onclick事件,所有查看网站的人都能看到代码 ...

随机推荐

  1. Unable to list target platforms. Please make sure the android sdk path is correct. See the Console for more details.

    在android上发布遇到 androidSDK无法找到的问题 http://www.jianshu.com/p/fe4c334ee9fe

  2. boolean类型的特殊的get和set方法

    public class D { private boolean a; public boolean isA() { return a; } public void setA(boolean a) { ...

  3. Hibernate级联及控制反转的增删改查

    在JavaHibernate中,双向多对一的操作一直是一个重点难点,本篇文章就是来探讨这个问题. 双向多对一:一个班级对应多个学生,多个学生同属于一个班级,通过班级信息可以查到班级内的学生,通过学生可 ...

  4. PS如何使用制作图片投影效果

    如果仅仅是同样大小的背景(灰色或者黑色),则只要新建一个和比原图大三个像素的文件(比如这里原图片为100×100,我就建立一个103×103的文件)把图片放在左上角,剩下的部分填充灰色或者黑色.然而这 ...

  5. Git版本管理

    1.显示当前工作目录 pwd 2.把当前目录初始化为git可以管理的仓库 git init 3.把文件添加到仓库 git add xxx.txt 4.告诉git,把文件提交到仓库 .-m后面输入的是本 ...

  6. hdu5303(2015多校2)--Delicious Apples(贪心+枚举)

    Delicious Apples Time Limit: 5000/3000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Other ...

  7. HDU 5308 规律+模拟

    给出N个数字N,要把全部数字用完.使用+-*/最后变为24.中间运算能够有有浮点数 对于1-14直接打表 15以上的能够通过13个同样数字得到24.然后使后面的数所有运算为0相加就可以 贴一发官方题解 ...

  8. 【VBA】获取模板保存的路径

    使用VBA如何获取模板保存的路径呢?具体代码如下: Sub 获取Excle模板保存路径() MsgBox "获取Excle模板保存路径:" & Application.Te ...

  9. 查看/设置MySQL数据库的事务隔离级别

    查看InnoDB存储引擎 系统级的隔离级别 和 会话级的隔离级别: mysql> select @@global.tx_isolation,@@tx_isolation; +---------- ...

  10. PriorityBlockingQueue优先队列的二叉堆实现

    转载请注明原创地址http://www.cnblogs.com/dongxiao-yang/p/6293807.html java.util.concurrent.PriorityBlockingQu ...