基於uwsgi的Web服務路由功能公升級

2022-08-14 14:30:21 字數 2843 閱讀 3181

手上乙個基於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...