Python从零开始编写轻量级Web框架(1)
编写一个轻量级的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