All Products
Search
Document Center

API Gateway:Use the Lua plug-in

Last Updated:Mar 20, 2025

Lua is a lightweight and highly efficient scripting language. In gateway development, Lua can be used to write and execute various gateway programs, such as API gateways, message gateways, and reverse proxies. Developers can use Lua to write scripts to implement features such as request routing, filtering, and authentication, and perform customized processing. Lua can be embedded into some proxies, such as NGINX and Envoy for request and response processing, log output, and other customized operations. In this topic, Lua is embedded into the Envoy proxy for request and response processing. This topic describes how to use Lua to print headers and bodies of requests and responses in logs.

Limits

The version of your Cloud-native API Gateway instance must be 2.0.0 or later.

Precautions

For security considerations, the following Lua libraries and functions are disabled by default in Cloud-native API Gateway.

  • debug.debug

  • debug.getfenv

  • debug.getregistry

  • dofile

  • io

  • loadfile

  • os.execute

  • os.getenv

  • os.remove

  • os.rename

  • os.tmpname

Procedure

  1. Log on to the Cloud-native API Gateway console.

  2. In the left-side navigation pane, click Instance. In the top navigation bar, select a region.

  3. On the Instance page, click the name of the gateway instance that you want to manage.

  4. In the left-side navigation tree, click Plug-in. Then, click Install Plug-in.

  5. In the search box, search by keyword lua. On the lua card, click Install. In the dialog box that appears, click Install and Configure.

  6. In the Rule Configurations panel, configure the following parameters:

    • In the Effective Scope section, select an application scope for the Lua plug-in.

    • If you select Operation-/Route-level Plug-in Rules or Domain-level plug-in rules for the Effective Scope parameter, click Add Rule on the right and configure parameters in the panel that appears. Write your Lua code in the Plug-in Rules field and click OK.

    • If you select Instance-level plug-in rules for the Effective Scope parameter, write your Lua code in the Plug-in Rules field on the right and click Save.

API references

For more information about the Lua APIs that are provided by cloud-native gateways, see Lua.

If you want to use JSON, you can use the following methods:

  • Introduce the JSON package: local json = require "json".

  • Serialize JSON data: local json_str = json.encode(obj).

  • Deserialize JSON data: local obj = json.decode(json_str).

If an error occurs during the serialization or deserialization, Lua calls the error function to return an error and terminates the current process.

Common use cases

Display complete request and response information in plug-in logs

  1. Log on to the Cloud-native API Gateway console.

  2. In the left-side navigation pane, click Instance. In the top navigation bar, select a region.

  3. On the Instance page, click the name of the gateway instance that you want to manage.

  4. In the left-side navigation tree, click Plug-in. Find the plug-in that you want to manage and click Rule Configuration in the Actions column.

  5. In the Rule Configurations panel, configure the following Lua code.

    Note

    In the sample code, only the following request bodies and response bodies of the content type are displayed. The body size cannot exceed 1,024 bytes (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
  6. Click the lua plug-in details page, click the Log tab and then click Enable Log Shipping.

  7. After you enable log shipping, logs of the plug-in are shipped to Simple Log Service and can be viewed in the console.

Add complete request and response information to access logs

  1. Log on to the Cloud-native API Gateway console.

  2. In the left-side navigation pane, click Instance. In the top navigation bar, select a region.

  3. On the Instance page, click the name of the gateway instance that you want to manage.

  4. In the left-side navigation tree, click Plug-in. Find the plug-in that you want to manage and click Rule Configuration in the Actions column.

  5. In the Rule Configurations panel, configure the following Lua code.

  6. You can configure custom dynamic metadata for the access log parameters of a gateway. In this case, you must define the metadata in the plug-in. The following sample code defines four types of metadata information, which correspond to the request header, request body, response header, and response 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
  7. In the left-side navigation tree, click Parameters. In the Observability Parameters section, modify the log format. In the Adjust Log Format dialog box, add metadata items based on your business requirements. The corresponding data will be displayed in logs.

    image