手上乙個基於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 =functions[path](params)
deffoobar(params):
param1 = params.get("
p")
經過一段時間的使用後發現,在這種形式下每個函式的引數unpack與必要引數判斷都需要獨立進行,產生了很多重複**
並且,在參考了flask等框架的裝飾器形式之後,對路由部分進行了重構
def route(path="", required=none):defroute_func(func):
defparams_check_func(params):
args =inspect.getargspec(func)
for required_param in (var_required if required else
):
if required_param not
inparams:
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):defroute_func(func):
defparams_check_func(params):
args =inspect.getargspec(func)
var_required =required
ifnot
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
inparams:
raise paramserror("
%s is required
" %required_param)
ifnot args.varargs and
notargs.keywords:
for param_key in
params.keys():
if param_key not
inargs.args:
params.pop(param_key)
return func(**params)
global
functions
var_path =path
ifnot
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)
基於HttpListener的web伺服器
前面兩篇文章分別介紹了基於原始socket的web伺服器和基於tcplistener的web伺服器,本篇文章將繼續介紹另外一種基於httplistener的。httplistener進一步的簡化了http協議的監聽,僅需通過字串的方法提供監聽的位址和埠號以及虛擬路徑,就可以開始監聽工作了。設定字首,...
基於tornado的WEB服務
搭建乙個微型的web服務,監聽8000埠,如有接收到客戶端的網頁請求,根據請求的路徑 返回 對應的資訊。監聽埠設定 命令列或是python指令碼內?如何設定 web.py程式執行時,必須監聽伺服器端口,以便向客戶提供服務。如果我們將埠,定義在指令碼 內部,那麼,如果想要改動監聽的埠,我們必須要修改指...
基於TcpListener的web伺服器
上篇文章根據 asp.net 本質論 書上提供的例子,實現了乙個簡單的web伺服器,本篇文章將介紹另一種實現方式 基於tcplistener的web伺服器。命名空間system.net.sockets下的tcplistener類簡化了基於tcp協議的監聽程式。using system using s...