Lua是一種輕量級、高效的指令碼語言,在雲原生API Gateway開發中,Lua可以用於編寫和執行各種網關程式,例如API Gateway、訊息網關、反向 Proxy等。通過Lua指令碼,開發人員可以實現請求的路由、過濾、鑒權等功能,並進行定製化的處理。在一些代理中,比如Nginx和Envoy,Lua可以被嵌入用於處理請求和響應,並進行日誌輸出和其他定製化操作。本文中的Lua指令碼用於在Envoy代理中處理請求和響應,並將請求和響應的頭部和本文資訊以日誌的形式輸出。
使用限制
雲原生API Gateway版本為2.0.0以上。
注意事項
出於安全考慮,雲原生API Gateway預設禁用以下Lua庫和函數。
debug.debug
debug.getfenv
debug.getregistry
dofile
io
loadfile
os.execute
os.getenv
os.remove
os.rename
os.tmpname
操作步驟
在左側導覽列,選擇執行個體,並在頂部功能表列選擇地區。
在執行個體頁面,單擊目標網關執行個體名稱。
在左側導覽列,選擇外掛程式,單擊安裝外掛程式。
在安裝外掛程式頁面的搜尋方塊中搜尋lua,找到lua資源卡片並單擊安裝並配置。
在規則配置頁面,配置如下參數。
在生效範圍處,選擇Lua外掛程式的應用範圍。
選擇介面/路由級外掛程式規則或網域名稱級外掛程式規則時單擊添加規則,在添加規則彈框中配置相關參數,然後在外掛程式規則框中填寫Lua代碼,最後單擊確定。
選擇執行個體級外掛程式規則時,在外掛程式規則框中填寫Lua代碼,最後單擊儲存。
API參考
關於網關提供的Lua API詳細資料,請參見Lua。
如果在序列化或還原序列化時出現錯誤,Lua將調用error函數拋出錯誤,並終止當前處理。
常見用例
列印完整的請求應答資訊到外掛程式日誌
在左側導覽列,選擇執行個體,並在頂部功能表列選擇地區。
在執行個體頁面,單擊目標網關執行個體名稱。
在左側導覽列,選擇外掛程式,然後單擊目標外掛程式操作列下的規則配置。
在規則配置中配置以下Lua代碼。
說明根據此代碼配置,只會列印以下
content-type類型的請求Body和應答Body,且Body不能超過1024位元組(1 KB)。application/x-www-form-urlencoded
application/json
text/plain
local maxBodySize = 1024 function check_content_readable(type) if type == nil then return false end if string.find(type, "application/x-www-form-urlencoded",1,true) or string.find(type, "application/json",1,true) or string.find(type, "text/plain",1,true) then return true end return false end function envoy_on_request(request_handle) local headers = request_handle:headers() local headersStr = "" local contentType for key, value in pairs(headers) do if key == "content-type" then contentType = value end headersStr = headersStr .. key .. "=" .. value .. ", " end request_handle:streamInfo():dynamicMetadata():set("envoy.lua","request_headers",headersStr) local requestBody = "" if check_content_readable(contentType) then for chunk in request_handle:bodyChunks() do if (chunk:length() > 0) then requestBody = requestBody .. chunk:getBytes(0, chunk:length()) end if (#requestBody > maxBodySize) then requestBody = requestBody .. "<truncated>" break end end end request_handle:streamInfo():dynamicMetadata():set("envoy.lua","request_body",string.gsub(requestBody,"\n","\\n")) end function envoy_on_response(response_handle) local headers = response_handle:headers() local headersStr = "" local contentType local contentEncoding = false for key, value in pairs(headers) do if key == "content-type" then contentType = value elseif key == "content-encoding" then contentEncoding = true end headersStr = headersStr .. key .. "=" .. value .. ", " end local responseBody = "" if check_content_readable(contentType) and not contentEncoding then for chunk in response_handle:bodyChunks() do if (chunk:length() > 0) then responseBody = responseBody .. chunk:getBytes(0, chunk:length()) end if (#responseBody > maxBodySize) then responseBody = responseBody .. "<truncated>" break end end end local reqHeaders = "" local reqBody = "" local metadata = response_handle:streamInfo():dynamicMetadata():get("envoy.lua") if metadata ~= nil then local headers = response_handle:streamInfo():dynamicMetadata():get("envoy.lua")["request_headers"] if headers ~= nil then reqHeaders = headers end local body = response_handle:streamInfo():dynamicMetadata():get("envoy.lua")["request_body"] if body ~= nil then reqBody = body end end response_handle:logInfo("request Headers: [" .. reqHeaders .. "] request Body: [" .. string.gsub(reqBody,"\n","\\n") .. "] response Headers: [" .. headersStr .. "] response Body: [" .. string.gsub(responseBody,"\n","\\n") .. "]") end單擊目標Lua外掛程式,選擇日誌頁簽,單擊立即開啟日誌投遞功能。
日誌投遞開啟後,外掛程式日誌將投遞到SLS並可在頁面中查看。
如下所示,可以使用訪問日誌中的
request-id,在Lua外掛程式日誌中找到完整的請求和響應資訊。
將完整的請求應答資訊添加到訪問日誌
在左側導覽列,選擇執行個體,並在頂部功能表列選擇地區。
在執行個體頁面,單擊目標網關執行個體名稱。
在左側導覽列,選擇外掛程式,然後單擊目標外掛程式操作列下的規則配置。
在規則配置中配置以下Lua代碼。
網關的訪問日誌參數支援配置自訂動態中繼資料,首先需要在外掛程式中定義中繼資料。以下代碼一共定義了四個中繼資料資訊,分別對應要求標頭、請求Body、回應標頭、響應Body:
envoy.lua:request_headers
envoy.lua:request_body
envoy.lua:response_headers
envoy.lua:response_body
local maxBodySize = 1024 function check_content_readable(type) if type == nil then return false end if string.find(type, "application/x-www-form-urlencoded",1,true) or string.find(type, "application/json",1,true) or string.find(type, "text/plain",1,true) then return true end return false end function envoy_on_request(request_handle) local headers = request_handle:headers() local headersStr = "" local contentType for key, value in pairs(headers) do if key == "content-type" then contentType = value end headersStr = headersStr .. key .. "=" .. value .. ", " end request_handle:streamInfo():dynamicMetadata():set("envoy.lua","request_headers",headersStr) local requestBody = "" if check_content_readable(contentType) then for chunk in request_handle:bodyChunks() do if (chunk:length() > 0) then requestBody = requestBody .. chunk:getBytes(0, chunk:length()) end if (#requestBody > maxBodySize) then requestBody = requestBody .. "<truncated>" break end end end request_handle:streamInfo():dynamicMetadata():set("envoy.lua","request_body",string.gsub(requestBody,"\n","\\n")) end function envoy_on_response(response_handle) local headers = response_handle:headers() local headersStr = "" local contentType local contentEncoding = false for key, value in pairs(headers) do if key == "content-type" then contentType = value elseif key == "content-encoding" then contentEncoding = true end headersStr = headersStr .. key .. "=" .. value .. ", " end response_handle:streamInfo():dynamicMetadata():set("envoy.lua","response_headers",headersStr) local responseBody = "" if check_content_readable(contentType) and not contentEncoding then for chunk in response_handle:bodyChunks() do if (chunk:length() > 0) then responseBody = responseBody .. chunk:getBytes(0, chunk:length()) end if (#responseBody > maxBodySize) then responseBody = responseBody .. "<truncated>" break end end end response_handle:streamInfo():dynamicMetadata():set("envoy.lua","response_body",string.gsub(responseBody,"\n","\\n")) end在左側導覽列,選擇參數配置。在可觀測性參數地區對日誌格式進行調整。在日誌格式調整彈框中添加對應的中繼資料資訊,就可以在訪問日誌中看到對應的資訊。
