すべてのプロダクト
Search
ドキュメントセンター

API Gateway:Lua プラグインを使用する

最終更新日:Feb 15, 2025

Lua は軽量で高効率なスクリプト言語です。ゲートウェイ開発では、Lua を使用して、API ゲートウェイ、メッセージゲートウェイ、リバースプロキシなど、さまざまなゲートウェイプログラムを作成し、実行できます。開発者は Lua を使用して、リクエストのルーティング、フィルタリング、認証などの機能を実装するスクリプトを作成し、カスタマイズされた処理を実行できます。 Lua は、リクエストとレスポンスの処理、ログ出力、その他のカスタマイズされた操作のために、NGINX や Envoy などの一部のプロキシに埋め込むことができます。このトピックでは、Lua はリクエストとレスポンスの処理のために Envoy プロキシに埋め込まれています。このトピックでは、Lua を使用してリクエストとレスポンスのヘッダーと本文をログに出力する方法について説明します。

制限事項

クラウドネイティブ 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

手順

  1. クラウドネイティブ API Gateway コンソール にログオンします。

  2. 左側のナビゲーションウィンドウで、[インスタンス] をクリックします。上部のナビゲーションバーで、リージョンを選択します。

  3. [インスタンス] ページで、管理するゲートウェイインスタンスの名前をクリックします。

  4. 左側のナビゲーションツリーで、[プラグイン] をクリックします。次に、[プラグインのインストール] をクリックします。

  5. 検索ボックスで、キーワード lua で検索します。[lua] カードで、[インストール] をクリックします。表示されるダイアログボックスで、[インストールと構成] をクリックします。

  6. [ルールの構成] パネルで、次のパラメーターを構成します。

    • [有効範囲] セクションで、Lua プラグインのアプリケーション範囲を選択します。

    • [操作/ルートレベルのプラグインルール] または [ドメインレベルのプラグインルール] を [有効範囲] パラメーターに選択した場合は、右側の [ルールの追加] をクリックし、表示されるパネルでパラメーターを構成します。[プラグインルール] フィールドに Lua コードを記述し、[OK] をクリックします。

    • [インスタンスレベルのプラグインルール] を [有効範囲] パラメーターに選択した場合は、右側の [プラグインルール] フィールドに Lua コードを記述し、[保存] をクリックします。

API リファレンス

クラウドネイティブゲートウェイによって提供される Lua API の詳細については、「Lua」をご参照ください。

JSON を使用する場合は、次のメソッドを使用できます。

  • JSON パッケージを導入します: local json = require "json"

  • JSON データをシリアル化します: local json_str = json.encode(obj)

  • JSON データをデシリアライズします: local obj = json.decode(json_str)

シリアル化またはデシリアライズ中にエラーが発生した場合、Lua は error 関数を呼び出してエラーを返し、現在のプロセスを終了します。

一般的なユースケース

プラグインログに完全なリクエストとレスポンスの情報を表示する

  1. クラウドネイティブ API Gateway コンソール にログオンします。

  2. 左側のナビゲーションウィンドウで、[インスタンス] をクリックします。上部のナビゲーションバーで、リージョンを選択します。

  3. [インスタンス] ページで、管理するゲートウェイインスタンスの名前をクリックします。

  4. 左側のナビゲーションツリーで、[プラグイン] をクリックします。管理するプラグインを見つけ、[アクション] 列の [ルールの構成] をクリックします。

  5. [ルールの構成] パネルで、次の Lua コードを構成します。

    説明

    サンプルコードでは、content type の次のリクエスト本文とレスポンス本文のみが表示されます。本文のサイズは 1,024 バイト (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. lua プラグインの詳細ページをクリックし、[ログ] タブをクリックして、[ログ配布を有効にする] をクリックします。

  7. ログ配布を有効にすると、プラグインのログは Simple Log Service に配布され、コンソールで表示できます。

アクセスログに完全なリクエストとレスポンス情報を追加する

  1. クラウドネイティブ API Gateway コンソール にログオンします。

  2. 左側のナビゲーションウィンドウで、[インスタンス] をクリックします。上部のナビゲーションバーで、リージョンを選択します。

  3. [インスタンス] ページで、管理するゲートウェイインスタンスの名前をクリックします。

  4. 左側のナビゲーションツリーで、[プラグイン] をクリックします。管理するプラグインを見つけ、[アクション] 列の [ルールの構成] をクリックします。

  5. [ルールの構成] パネルで、次の Lua コードを構成します。

  6. ゲートウェイのアクセスログパラメーターのカスタム動的メタデータを構成できます。この場合、プラグインでメタデータを定義する必要があります。次のサンプルコードでは、リクエストヘッダー、リクエスト本文、レスポンスヘッダー、レスポンス本文に対応する 4 種類のメタデータ情報を定義しています。

    • 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. 左側のナビゲーションツリーで、[パラメーター] をクリックします。[可観測性パラメーター] セクションで、ログ形式を変更します。[ログ形式の調整] ダイアログボックスで、ビジネス要件に基づいてメタデータ項目を追加します。対応するデータがログに表示されます。

    image