Python从零开始编写轻量级Web框架(3)

编写一个轻量级的Web应用框架

最近阅读了Flask的源码,弄懂了原理之后就想尝试来实现自己的一个Web框架。

因为大部分的实现思路都参照Flask0.1版本,也就是最初版本的思路。所用的基本库是werkzeug。

框架的完整代码都放在了Github上,之后会继续更新:https://github.com/jyz0309/WebFrame
求star,球球了T_T

在完成了ORM模块之后,接下来为框架增加session的功能,session的功能原本是想不完全按照flask的实现,但是发现有点问题,所以还是按照了flask框架的基本思路来实现,也就是底层库的SecureCookie来实现,并通过栈的方式来查找。

import os
from werkzeug.wrappers import BaseRequest, BaseResponse
from werkzeug.exceptions import HTTPException, MethodNotAllowed, \
     NotImplemented, NotFound
from werkzeug.serving import run_simple
from werkzeug.local import LocalStack,LocalProxy
from jinja2 import Environment,FileSystemLoader
from werkzeug.contrib.securecookie import SecureCookie
def render_template(template_name,**context):
    '''
    :param template_name:模板名字
    :param context: 传递给模板的字典参数
    :return: template
    '''
    template_path = os.path.join(os.getcwd(), 'templates')
    jinja_env = Environment(loader=FileSystemLoader(template_path), autoescape=True)
    return jinja_env.get_template(template_name).render(context)


class Request(BaseRequest):
    """Encapsulates a request."""


class Response(BaseResponse):
    """Encapsulates a response."""

class _RequestContext(object):
    """请求上下文(request context)包含所有请求相关的信息。它会在请求进入时被创建,
    然后被推送到_request_ctx_stack,在请求结束时会被相应的移除。它会为提供的
    WSGI环境创建URL适配器(adapter)和请求对象。
    """
    def __init__(self, app, environ):
        self.app = app
        self.test = 1
        self.request = Request(environ)
        self.session = app.open_session(self.request)

    def __enter__(self):
        # print(self.test)
        _request_stk.push(self)

    def __exit__(self, exc_type, exc_value, tb):
        # 在调试模式(debug mode)而且有异常发生时,不要移除(pop)请求堆栈。
        # 这将允许调试器(debugger)在交互式shell中仍然可以获取请求对象。
        if tb is None or not self.app.debug:
            _request_stk.pop()


class View(object):
    """Baseclass for our views."""
    def __init__(self):
        self.methods_meta = {
            '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_meta:
            return self.methods_meta[request.method](request, *args, **options)
        else:
            return '<h1>Unsupported require method</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):
    # 如果设置了密钥,加密组件可以使用它来作为cookies或其他东西的签名。
    secret_key = None
    debug = True
    def __init__(self):
        self.url_map = {}
        # self.view_functions = {}

    def request_context(self,environ):
        return _RequestContext(self,environ)

    def process_response(self,response):
        session = _request_stk.top.session
        if session is not None:
            self.save_session(session,response)
        return response

    def wsgi_app(self,environ,start_response):

        with self.request_context(environ):
            req = Request(environ)
            response = self.dispatch_request(req)
            if response:#如果可以找到正确的匹配项
                response = Response(response, content_type='text/html; charset=UTF-8')
                response = self.process_response(response)
            else:#找不到,返回404NotFound
                response = Response('<h1>404 Not Found<h1>', content_type='text/html; charset=UTF-8', status=404)
            return response(environ, start_response)

    def open_session(self, request):
        """创建或打开一个新的session,默认的实现是存储所有的session数据到一个签名的cookie中,前提是secret_key属性被设置
        :param request: Request实例
        """
        key = self.secret_key
        if key is not None:
            return SecureCookie.load_cookie(request, 'session', secret_key=key)

    def save_session(self, session, response):
        #print(response)
        if session is not None:
             session.save_cookie(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)
                #print(response)
            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()
             # self.url_map[url['url']] = url['func'].get_func()


    def run(self, port=8090, ip='127.0.0.1', debug=True):
        run_simple(ip, port, self, use_debugger=debug, use_reloader=True)

_request_stk = LocalStack()
current_app = LocalProxy(lambda: _request_stk.top.app)
request = LocalProxy(lambda: _request_stk.top.request)
session = LocalProxy(lambda: _request_stk.top.session)

测试函数

from app import App,View,session
import json


class Index(View):
    def GET(self,request,x):
        #session['hello'] = 2
        return x
    def POST(self,request):
        print(json.dumps(request.form['color']))
        return json.dumps({'1':'hello'})

class Test(View):
    def GET(self,request):
        # print(session['hello1'])
        return 'test'
    def POST(self,request):
        return json.dumps({'2':'hello'})


urls = {'/test':Test}
app = App()
app.secret_key = 'password'
app.add_url_rule(urls)
app.run()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值