例如Flask
,在处理方法上加一个@app.route('xxx')
即可。
这是怎么实现的呢?
前言
开始的时候思路有点飘,想的是这个思路:
- 扫描指定的包
- 动态获取module内的
属性和方法 - 判断方法是否有装饰器,装饰器是否匹配,以及获取装饰器的参数
- 根据收集的方法和相应参数处理网络请求
搜了很多,感觉这两篇有点东西:
但这个路数实际上有点歪,本质上还是对装饰器理解不够透彻啊。。
实现
在写装饰器的时候,注意在函数装配时,将参数、函数等相关信息写入解析链即可。
这样在来了请求时,根据解析链逐条匹配进行处理。
web/url.py
from urllib.parse import urlparse, parse_qs
from functools import wraps
import inspect
chains = {}
class get(object):
def __init__(self, url = ""):
self.url = url
def __call__(self, func):
@wraps(func)
def run(*args, **kwargs):
return func(*args, **kwargs)
# 写入函数的参数,供解析的时候初始化使用
run.params = inspect.signature(func).parameters
# 加入解析链
chains[self.url] = run
return run
def deal_http_get(url: str):
for url_pattern, func in chains.items():
if(url.startswith(url_pattern)):
# 从url解析出参数信息
params = parse_qs(urlparse(url).query)
kargs = {}
# 初始化参数
for param, value in func.params.items():
final_val = None
if param in params:
# 从url里面取
final_val = params[param][0]
elif value.default != inspect._empty:
# 没有的话再尝试从默认值里面取
final_val = value.default
# 进行赋值
kargs[param] = final_val
func(**kargs)
break;
url_test.py
from web import url
@url.get(url = "/hello")
def sayHello(key = '你好'):
print("sayHello: ", key)
@url.get(url = "/fxxk")
@url.get(url = "/fccku")
def sayJ8(key):
print("sayJ8: ", key)
@url.get(url = "/goodbye")
@url.get(url = "/byebye")
def sayBye(key = '再见'):
print("sayBye: ", key)
if __name__ == "__main__":
#假设来了HTTP GET请求
url_path = "/hello"
url.deal_http_get(url_path)
url_path = "/hello?key=哈哈哈"
url.deal_http_get(url_path)
url_path = "/fxxk"
url.deal_http_get(url_path)
url_path = "/fccku?key=fxxk u"
url.deal_http_get(url_path)
url_path = "/goodbye"
url.deal_http_get(url_path)
url_path = "/byebye?key=呜呜呜"
url.deal_http_get(url_path)