• 基于uwsgi的Web服务路由功能升级


    手上一个基于uwsgi开发的后台服务,接收GET请求,使用QUERY_STRING作为参数。

    最开始的时候,路由功能使用的是if else的结构,大致如下

    path = env["PATH_INFO"]
    param = parse_query_string(env["QUERY_STRING"])
    if path == "foo1/bar1":
        fooBar1(param)
    elif path == "foo2/bar2":
        fooBar2(param)

    为了方便管理并且美化代码,调整为使用路由字典的形式

    funcion = {"foo/bar":fooBar}
    
    functions[path](params)
    
    def fooBar(params):
        param1 = params.get("p")

    经过一段时间的使用后发现,在这种形式下每个函数的参数unpack与必要参数判断都需要独立进行,产生了很多重复代码

    并且,在参考了flask等框架的装饰器形式之后,对路由部分进行了重构

    def route(path="", required=None):
        def route_func(func):
            def params_check_func(params):
                args = inspect.getargspec(func)
                for required_param in (var_required if required else []):
                    if required_param not in params:
                        raise ParamsError("%s is required" % required_param)
                return func(**params)
            global functions
            functions[path] = params_check_func
            return params_check_func
        return route_func
    
    @route("foo/bar", ["p"])
    def fooBar(p, *args, **kwargs):
        return do_sth(p)

    其中因为参数利用了Python的可变变量功能,直接从QUERY_STRING解析获得,为了避免输入参数中附加了不必要的参数,所以使用*args, **kwargs的结构将多余的参数存储并忽略掉

    以避免多余的参数使函数因参数数量不符造成报错

    每个函数都增加*args, **kwargs的参数显得多余,同时发现,每个函数的必须参数在函数定义的参数列表中已经可以体现,

    具体思路是:

    使用 inspect.getargspec(func)获得参数的具体参数列表

    则其中的args.defaults即为有默认值参数的默认值,使用len(args.defaults)获取有默认值参数的个数

    那么args.args[:-len(args.defaults)]就是必须参数的列表,因为在定义中,有默认值的参数必须在无默认值参数的后面

    进一步,如果没有args.varargs和not args.keywords即可变参数,则将所有多余的参数过滤

    同时经过统一格式化的参数名,也可以直接映射到相应的路径

    那么在改进之后的代码则如下

    def route(path="", required=None):
        def route_func(func):
            def params_check_func(params):
                args = inspect.getargspec(func)
                var_required = required
                if not var_required:
                    var_required = [arg for arg in args.args[:-len(args.defaults)]]
                for required_param in (var_required if var_required else []):
                    if required_param not in params:
                        raise ParamsError("%s is required" % required_param)
                if not args.varargs and not args.keywords:
                    for param_key in params.keys():
                        if param_key not in args.args:
                            params.pop(param_key)
                return func(**params)
            global functions
            var_path = path
            if not var_path:
                var_path = "/%s/" % func.func_name.replace("__", "/")
            functions[var_path] = params_check_func
            return params_check_func
        return route_func
    
    @route()
    def foo__bar(p1, p2=1):
        return do_sth(p1, p2)
  • 相关阅读:
    使用U盘做最官方纯净的高压缩级别的w10系统,享受急速5秒开机
    Nginx设置浏览器缓存
    --with-http_sub_module模块
    --with-http_random_index_module模块
    --with-http_stub_status_module模块
    Nginx常见问题
    secure_link_module模块
    nginx编译安装新模块
    使用Ubuntu搭建Web服务器
    [BJDCTF 2nd]假猪套天下第一
  • 原文地址:https://www.cnblogs.com/ruizhang3/p/6687416.html
Copyright © 2020-2023  润新知