想在api服務器里實現一個acl的功能,對某些請求(需要登錄,需要檢查appkey,需要限制頻次等)做限制,對某些起始狀態(比如登陸)或者終結狀態(比如報錯)的請求放行。
因為lua里木有switch case,因此通過一個acl_list的table去查找規則,因為需要限制的請求種類比較多,就把rule_check_token當成默認值了,一看是是這麼寫的:
		
		
			
			
			
			
				
					
				| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | local _M = {     ACL_PASS = 0,     ACL_DENIED = 1, }   function _M.rule_always_pass(self)     return _M.ACL_PASS end   function _M.rule_check_token(query)     if query == nil then         return _M.ACL_DENIED     end     local token = query['token'] or ngx.req.get_headers()['Authorization']     local uid = query['uid']     -- ... end   _M.acl_list = setmetatable({     ['error'] = _M.rule_always_pass,     ['user/login'] = _M.rule_always_pass, }, {     __index = _M.rule_check_token })   return _M | 
				
			 
		 
然而卻會在local token= xxxx那一行報stack overflow,想了半天也發現哪裡有無限遞歸,因為query傳進來的是http請求的query string解析出的鍵值對錶。
把query打印出來一看,發現竟然是這個模塊本身……
仔細看了文檔才知道,原來__index後面的值是一個function時,lua會調用這個function去獲得不存在的鍵,並且第一個參數是模塊本身(即_M,一個table)。在這個例子里:
- 調用一個非默認規則的api
- lua調用了rule_check_token
- 參數query被傳入了_M本身
- 運行到local token= xxxx這一行
- 這個table里(_M)又沒有token這個鍵
- 回到2
所以就死循環了
 
所以要好好看文檔
 
解決方法是可以套一個function
		
		
			
			
			
			
				
					
				|  |  __index = function() return _M.rule_check_token end | 
				
			 
		 
 
貼一個打印table的工具,方便調試:
		
		
			
			
			
			
				
					
				|  | function print_r(tbl, pref)     for k,v in pairs(tbl) do          if type(v) == 'table' then             print((pref or "|-"), k, "\t", "<table>")             _print_r(v, "  "..(pref or "|-"))         else             if type(v) == 'function' then                 v = "   <function>"             end             print((pref or "|-"), k, "\t", v)         end     end end | 
				
			 
		 
可以打印出如下形式:
		
		
			
			
			
			
				
					
				|  | |-_VERSION      0.01 |-rule_always_pass         <function> |-ACL_DENIED    1 |-acl_list      <table>   |-error          <function>   |-user/login     <function> |-ACL_PASS      0 |-rule_check_token         <function> | 
				
			 
		 
使用openresty請自行改寫成local function和ngx.say的形式