zoukankan      html  css  js  c++  java
  • 动手写一个简单的Web框架(Werkzeug路由问题)

    动手写一个简单的Web框架(Werkzeug路由问题)

    继承上一篇博客,实现了HelloWorld,但是这并不是一个Web框架,只是自己手写的一个程序,别人是无法通过自己定义路由和返回文本,来使用的,所以在这篇博客中,将实现一个简单的路由自定义功能

    首先引入werkzeug中的两个工具,分别是Map,和Rule,需要通过以下代码引入

    from werkzeug.routing import Map, Rule
    

    这两个可以完成路由定义和匹配的基本实现,其次,还引入到werkzeug中的Request对象来处理environ

    首先,我们看一下Map和Rule的使用:

    from werkzeug.routing import Rule, Map
    url_map = Map([
        Rule('/', endpoint='index', methods=['GET']),
        Rule('/about', endpoint='about', methods=['GET']),
    ])
    print(url_map)
    

    上面这段代码定义了一个url_map的对象,它是Map的实例,传入参数是一个列表,在列表里面,存储着路由,我们一个一个来看,Rule中首先传入的是路由参数,代表着访问的路由,然后是methods,用于标记请求的方法,再接着是endpoint,这个参数其实只是给这个路由起一个名字,但是关系确是重大的,我们下一步进行的视图函数的定义以及和路由绑定在一起就离不开endpoint这个参数,它可由使用者自行定义,也可默认为视图函数的函数名。可以看到打印出来的url_map,是路由和endpoint以及methods一一对应的

    Map中有一个add方法,可以用于添加新的路由

    from werkzeug.routing import Rule, Map
    url_map = Map([
        Rule('/', endpoint='index', methods=['GET']),
        Rule('/about', endpoint='about', methods=['GET']),
    ])
    url_map.add(Rule('/hello', endpoint='hello', methods=['GET']))
    print(url_map)
    

    可以看到运行结果

    关于路由的匹配问题,可以使用Map的match来进行匹配,用法只需传入路由,即可获取endpoint,在运行前,需要使用Map中的bind,来实例化一个urls,它必需的参数为hostname,还有其他的参数可自行研究,我们需要根据实例化出的urls中的match来实现路由的匹配:

    from werkzeug.routing import Rule, Map
    url_map = Map([
        Rule('/', endpoint='index', methods=['GET']),
        Rule('/about', endpoint='about', methods=['GET']),
    ])
    url_map.add(Rule('/hello', endpoint='hello', methods=['GET']))
    print(url_map)
    urls = url_map.bind('127.0.0.1:5000')
    url = '/'
    endpoint = urls.match(path_info=url)
    print(endpoint)
    

    运行结果

    看到,匹配到了路由的endpoint

    那么,endpoint要怎么使用呢?

    我们在添加视图函数的时候,只是添加了路由,我们对于视图函数的存储还没有实现,其实,这里需要自己定义一个字典,用于存储endpoint和视图函数的键值对,这样,就可以通过获取和存入的endpoint来实现获取和存入视图函数,这部分代码就整合到所有代码中:

    from werkzeug.wrappers import Response, Request
    from werkzeug.serving import run_simple
    from werkzeug.routing import Map, Rule
    
    class Jlask(object):
        # 初始化url_map和存储endpoint对应视图函数
        # 这里是一个小坑,不能再__init__中初始化,这样会使得在类被调用的时候,执行了初始化的代码,导致原先创建的路由都丢失
        url_map = Map([])
        endpoint_dict = {}
    
        def dispatch_request(self, request):
            # 获取请求的路由
            url = request.path
            urls = self.url_map.bind('127.0.0.1:5000')
            # 匹配得到endpoint
            endpoint = urls.match(path_info=url)[0]
            # 获取到视图函数处理得结果
            view_func = self.endpoint_dict[endpoint](request)
            return Response(view_func)
    
        def wsgi_app(self, environ, start_response):
            # 启动
            # 实例化request,存入environ,这里的request就是werkzeug中对于environ的处理,可以通过request来获取各种请求信息
            request = Request(environ)
            # 调用dispatch_request解析url,得到对应的视图函数处理的结果
            response = self.dispatch_request(request)
            return response(environ, start_response)
    
        def __call__(self, environ, start_response):
            # 调用到wsgi_app,来执行url对应视图函数
            return self. wsgi_app(environ, start_response)
    
    
        def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
            # 获取请求方法
            methods = options.pop('methods', None)
            # 如果没有定义endpoint,就用试图函数的名字
            if endpoint is None:
                endpoint = view_func.__name__
                # 生成rule
                # rule: 定义的路由
                self.url_map.add(Rule(rule, endpoint=endpoint, methods=methods))
                # 存储endpoint对应的视图函数
                self.endpoint_dict[endpoint] = view_func
                # print(self.endpoint_dict)
                # print(self.url_map)
    
    app = Jlask()
    
    
    def Hello(request):
        return "Hello World"
    app.add_url_rule(rule='/', view_func=Hello, methods=['GET'])
    
    
    
    if __name__ == '__main__':
        run_simple('127.0.0.1', 5000, Shortly())
    

    到此就完成了简单得包含路由匹配功能的“Web框架”


    更新:

    对于自定义的视图函数,需要考虑使用者是否自己构造Response对象,所以需要在dispatch_request中对调用的视图函数返回值进行判断,如果是字符串对象,就构造Response,否则就直接返回

    def dispatch_request(self, request):
        url = request.path
        urls = self.url_map.bind('127.0.0.1:5000')
        endpoint = urls.match(path_info=url)[0]
        view_func = self.endpoint_dict[endpoint](request)
        if isinstance(view_func, str):
            return Response(view_func)
        else:
            return view_func
    
  • 相关阅读:
    什么是webview
    juqery.fn.extend和jquery.extend
    LeetCode
    5. Longest Palindromic Substring
    42. Trapping Rain Water
    11. Container With Most Water
    621. Task Scheduler
    49. Group Anagrams
    739. Daily Temperatures
    3. Longest Substring Without Repeating Characters
  • 原文地址:https://www.cnblogs.com/JoshuaYu/p/12951160.html
Copyright © 2011-2022 走看看