编写一个轻量级的Web应用框架
最近阅读了Flask的源码,弄懂了原理之后就想尝试来实现自己的一个Web框架。
因为大部分的实现思路都参照Flask0.1
版本,也就是最初版本的思路。所用的基本库是werkzeug
。
框架的完整代码都放在了Github上,之后会继续更新:https://github.com/jyz0309/WebFrame
求star,球球了T_T
总体思想:
按照flask的最基本功能的实现思想,首先建立url_map
的字典进行url
和视图函数的对应关系。
首先,当一个请求进来的时候,优先进入的是App
类的__call__()
回调函数,然后进入到wsgi_app
函数中,在这个函数中进行请求的分发处理以及响应的返回。
具体的实现在代码中的注释。
以下是代码:
import os
from werkzeug.wrappers import BaseRequest, BaseResponse
from werkzeug.exceptions import HTTPException, MethodNotAllowed, \
NotImplemented, NotFound
from werkzeug.serving import run_simple
from jinja2 import Environment,FileSystemLoader
class Request(BaseRequest):
"""对请求进行包装,可以自定义"""
class Response(BaseResponse):
"""对返回值进行包装,可以自定义."""
class View(object):
"""视图的基本类"""
def __init__(self):
self.methods = {
'GET': self.GET,
'POST': self.POST,
'PUT': self.PUT,
'DELETE': self.DELETE,
}
def GET(self):
raise MethodNotAllowed()
POST = DELETE = PUT = GET
def HEAD(self):
return self.GET()
def dispatch_request(self, request, *args, **options):
if request.method in self.methods:
return self.methods[request.method](request, *args, **options)
else:
return '<h1>不支持的请求方式!</h1>'
@classmethod
def get_func(cls):
# 匹配视图函数
def func(*args, **kwargs):
obj = func.view_class()
return obj.dispatch_request(*args, **kwargs)
func.view_class = cls
return func
class App(object):
def __init__(self):
self.url_map = {} # 记录url和视图函数的对应关系
def wsgi_app(self,environ,start_response):
req = Request(environ)
response = self.dispatch_request(req) #进行请求的分发
if response:#如果可以找到正确的匹配项
response = Response(response, content_type='text/html; charset=UTF-8')
else:#找不到,返回404NotFound
response = Response('<h1>404 Not Found<h1>', content_type='text/html; charset=UTF-8', status=404)
return response(environ, start_response)
def __call__(self, environ, start_response):
return self.wsgi_app(environ, start_response)
def dispatch_request(self, req):
try:
url = req.path
view = self.url_map.get(url,None)
if view:
response = view(req)
else:
response = None
except HTTPException as e:
response = e
return response
def add_url_rule(self,urls):
for url in urls:
self.url_map[url] = urls[url].get_func()
def run(self, port=8090, ip='127.0.0.1', debug=True):
#运行使用的是werkzeug的run_simple所创建的服务器
run_simple(ip, port, self, use_debugger=debug, use_reloader=True)
测试:
from app import App,View,session
import json
class Index(View):
def GET(self,request):
return "hello world"
def POST(self,request):
# print(json.dumps(request.form['color']))
return json.dumps({'1':'hello'})
class Test(View):
def GET(self,request):
return 'test'
def POST(self,request):
return json.dumps({'2':'hello'})
urls = {'/':Index,
'/test':Test}
app = App()
app.add_url_rule(urls)
app.run()
测试GET方法结果:
测试POST方法:
参考:
https://github.com/pallets/werkzeug/blob/0.12.2/examples/webpylike/webpylike.py