API Gateway を使わないで、無料で、グローバルIPアドレスをLambda関数に送る

published_with_changes 更新日:

labelamazon alexa labelBlynk labelIoT labelRaspberry pi

 AWSから請求書が来て、API Gateway が有料サービスであったことに気づきました。
AWS請求画面


無料で実現するため、Alexa 部屋の温度を教えて、第10版です。 自力では無理なので今回も、Google Gemini Logo に聞いて作ります。

これまでのIPアドレスを取得する方法は、2つとも有料のAPI Gateway を使う方法だったので、それを使わない方法を考えます。

  1. Raspberry Pi でグローバルIPを取得し、AWS Lambda に送信する手順でルータのIPアドレスを自動で取得することに成功しました。

    • この方法は ラズパイからのIPアドレス送信を5分おきに行いlambda関数を動かしていないと、IPアドレスを忘れてしまう欠点があります。


  1.  対策として、IPアドレスをDynamoDBに保存して、適時、呼び出す方法を考えました。

    • しかし、なぜか1秒おきだったり、1分おきだったりまちまちなのですが、ログが吐き出される現象があります。どうも、API Gatewayが悪さしているようでした。
    • 設定などを何度も見直しましたが、改善することはなく、結局はAPI Gateway を削除するしか、吐き出しを止める方法がありませんでした。
    • この現象により、約10日間で15,649 件のRequests が発生し、$0.54 が請求されることになりました。

専門知識がないので、生成AIが勧めてきたAPI Gatewayを使って構築したのが失敗でした。


目次
  1. API Gatewayを使わず、Lambda関数URL を使う
    1. 変更内容
  2. 1. Raspberry Piのスクリプト変更
    1. 変更内容
  3. 2. Lambda関数URLの有効化
    1. 2.1 Lambda関数URLの作成(AWS IAM認証)
    2. 2.2 IAMポリシーの作成
    3. 2.3 IAMユーザーの作成とポリシーのアタッチ
    4. 2.4 参考:Lambda関数URLの作成(認証なし)
  4. 3. Lambda関数の変更
    1. 変更内容
  5. まとめ: IPアドレスの優先順位:

API Gatewayを使わず、Lambda関数URL を使う

グローバルIPアドレスの取得はRaspberry Pi側で行い、取得したIPアドレスをLambda関数に送信することで、Lambda関数のIPアドレスではなく、ユーザーの実際のグローバルIPアドレスをDynamoDBに保存できます。

  • Raspberry Pi側でグローバルIPアドレスを取得する方法は、いくつかあります。
  • 例えば、http://checkip.amazonaws.com などの外部サイトにアクセスする方法や、ルーターのUPnP機能を利用する方法などがあります。
  • どちらの方法でも、Lambda関数の実行ロールにDynamoDBへの書き込み権限を付与する必要があります。
  • セキュリティ対策として、Lambda関数URLの場合は認証タイプを「AWS_IAM」にするか、Lambda関数内で認証処理を実装することを推奨します。

変更内容

  1. Raspberry Piのスクリプト変更:
    • Raspberry Piで動作しているPythonスクリプトを変更します。
    • API GatewayのエンドポイントにIPアドレスを送信していた部分を、Lambda関数URLにIPアドレスを送信するように変更します。
    • IPアドレスは、HTTPのPOSTリクエストの「body」に入れて送信します。

  1. Lambda関数URLの有効化:
    • AWSのLambdaコンソールで、変更したLambda関数の設定を開きます。
    • 「関数URL」という項目があるので、そこでLambda関数URLを有効にします。
    • 認証の設定は、今回は簡単に「認証なし」を選びます。ただし、セキュリティを考慮する場合は、「AWS IAM」を選択してください。
    • 有効にすると、Lambda関数URLが表示されます。これは、インターネットからLambda関数にアクセスするためのURLです。

  1. Lambda関数の変更:
    • 現在のLambda関数を少し変更します。
    • API Gatewayから送信されるイベントの形式ではなく、Lambda関数URLから送信されるイベントの形式に対応するように変更します。
    • 具体的には、Raspberry Piから送信されるIPアドレスを、イベントの「body」の部分から取得するように変更します。

  1. Alexaスキルの変更:
    • Alexaスキルは、変更する必要はありません。Lambda関数URLを使っても、これまで通りLambda関数を呼び出すことができます。

1. Raspberry Piのスクリプト変更

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import requests
import json
import datetime
import time
from requests_aws4auth import AWS4Auth

# Lambda関数URLに変更
LAMBDA_ENDPOINT = "YOUR_LAMBDA_FUNCTION_URL"  # Lambda関数URLを入力

# IAMユーザーの認証情報を設定
AWS_ACCESS_KEY_ID = "YOUR_AWS_ACCESS_KEY_ID"
AWS_SECRET_ACCESS_KEY = "YOUR_AWS_SECRET_ACCESS_KEY"
REGION = "ap-northeast-1"

auth = AWS4Auth(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, REGION, 'lambda')

def get_global_ip():
    """checkip.amazonaws.comでグローバルIPアドレスを取得"""
    try:
        response = requests.get("https://checkip.amazonaws.com")
        return response.text.strip()
    except requests.exceptions.RequestException as e:
        print(f"{datetime.datetime.now()} - Error getting global IP: {e}")
        return None

def send_ip_to_lambda(ip):
    """取得したIPアドレスをLambda関数URLに送信"""
    try:
        payload = {'ip': ip}
        headers = {'Content-Type': 'application/json'}
        response = requests.post(LAMBDA_ENDPOINT, json=payload, headers=headers, auth=auth)
        print(f"{datetime.datetime.now()} - Sent IP: {ip}, Response: {response.status_code}")
    except requests.exceptions.RequestException as e:
        print(f"{datetime.datetime.now()} - Error sending IP to Lambda: {e}")

if __name__ == "__main__":
    ip = get_global_ip()
    if ip:
        send_ip_to_lambda(ip)
Python

変更内容

1. LAMBDA_ENDPOINT の変更
  • API GatewayのエンドポイントからLambda関数URLに変更します。
  • YOUR_LAMBDA_FUNCTION_URL の部分を、実際のLambda関数URLに置き換えてください。
  • 以下は、IAMユーザーの認証情報の設定になります。(後で説明)2つの項目をIAM認証設定で得られた情報に置き換えてください。
    • YOUR_AWS_ACCESS_KEY_ID
    • YOUR_AWS_SECRET_ACCESS_KEY 
2. send_ip_to_lambda 関数の変更
  • headersからAPIキー(x-api-key)を削除します。Lambda関数URLではAPIキーは不要です。

2. Lambda関数URLの有効化

今回はセキュリティ強化のためIAM認証されたLambda関数URLを使います。
Lambda関数URLで「AWS IAM」認証を使用する場合は、IAMユーザーを作成し、ポリシーをアタッチする必要があります。

その手順を説明します。

2.1 Lambda関数URLの作成(AWS IAM認証)

  1. Lambdaコンソールを開きます。
    • AWSマネジメントコンソールにログインし、Lambdaのページを開きます。
  2. 対象のLambda関数を選択します。
    • readTemperature_local(例)関数を選択します。
  3. 「設定」タブを開きます。
  4. 左側のメニューから「関数URL」を選択します。
  5. 「関数URLを作成」ボタンをクリックします。
  6. 認証タイプで「AWS IAM」を選択します。
  7. 「保存」ボタンをクリックします。
これでLambda関数URLが作成され、URLが表示されます。
Lambdaコンソール画面


「設定」から「関数URL」
関数URL設定画面


「関数URLを作成」から「AWS IAM」を選択
認証タイプ選択画面

2.2 IAMポリシーの作成

Lambda関数URLで「AWS IAM」を選択した場合のIAM設定について説明します。

「AWS IAM」を選択すると、IAMユーザーまたはIAMロールにLambda関数URLへのアクセス権限を付与する必要があります。これにより、認証されたユーザーまたはロールのみがLambda関数を呼び出すことができます。

今回のケースでは、Raspberry PiからLambda関数URLを呼び出すために使用するIAMユーザーを作成することを推奨します。

IAMポリシーでは、どのAWSサービスへ、誰(ユーザ、ロール)がアクセスでき、どういった操作を許可するかを定義します。

  1. IAMコンソールを開きます。
  2. AWSマネジメントコンソールにログインし、IAMのページを開きます。
  3. 「ポリシー」を選択し、「ポリシーの作成」をクリックします。
  4. 「JSON」タブを選択し、以下のポリシーを貼り付けます。
    • リージョン、アカウントID、関数名を実際の値に置き換えます。
    • IAMポリシーはグローバルサービスであるため、特定のリージョンに限定されません。
{
      "Version": "2012-10-17",
      "Statement": [
          {
              "Effect": "Allow",
              "Action": "lambda:InvokeFunctionUrl",
              "Resource": "arn:aws:lambda:リージョン:アカウントID:function:関数名"
          }
      ]
  }
JSON
  1. 「次のステップ:タグ」をクリックします。
  2. 必要に応じてタグを追加し、「次のステップ:確認」をクリックします。
  3. ポリシー名を入力し、「ポリシーの作成」をクリックします。
    • IAMポリシーのポリシー名は、任意の名前を設定できます。ただし、ポリシーの内容を分かりやすく表す名前を付けることを推奨します。
    • 今回の場合、Lambda関数URLへのアクセス権限を付与するポリシーであるため、ポリシー名は LambdaFunctionUrlAccessPolicy にします。
IAMポリシー作成画面


2.3 IAMユーザーの作成とポリシーのアタッチ

Raspberry PiからLambda関数URLを呼び出す場合:
IAMユーザーを作成し、アクセスキーとシークレットアクセスキーを使用します。

  1. IAMコンソールを開きます。
    • AWSマネジメントコンソールにログインし、IAMのページを開きます。
  2. 「ユーザー」を選択し、「ユーザーを追加」をクリックします。
  3. ユーザー名を入力し、「次へ」をクリックします。
    • IAMユーザーのユーザー名は、任意の名前を設定できます。ただし、ユーザーの役割や目的を分かりやすく表す名前を付けることを推奨します。(例 ip-reporter-user)
  4. 「既存のポリシーを直接アタッチ」を選択し、作成したポリシー(LambdaFunctionUrlAccessPolicyなど)を検索してチェックボックスをオンにして、「次のステップ:タグ」をクリックします。
  5. 必要に応じてタグを追加し、「次のステップ:確認」をクリックします。
  6. ユーザー情報を確認し、「ユーザーの作成」をクリックします。
  7. アクセスキーIDシークレットアクセスキーを安全な場所に保存します。
  8. これらのキー情報を前述のRaspberry Piのスクリプトに書き込みます。

「ユーザー」から「ユーザーを追加」
IAMユーザー追加画面



ユーザー名を入力
IAMユーザー名入力画面

2.4 参考:Lambda関数URLの作成(認証なし)

IAM認証なしの場合は、IAMの設定は不要で簡単に関数URLを作成できます。

  1. Lambdaコンソールを開きます。
    • AWSマネジメントコンソールにログインし、Lambdaのページを開きます。
  2. 対象のLambda関数を選択します。
    • readTemperature_local関数を選択します。
  3. 「設定」タブを開きます。
  4. 左側のメニューから「関数URL」を選択します。
  5. 「関数URLを作成」ボタンをクリックします。
  6. 認証タイプで「認証なし」を選択します。
  7. 「保存」ボタンをクリックします。


3. Lambda関数の変更

変更内容

  1. IPアドレスの取得方法:
    • event['body']からJSON形式の文字列を取得し、json.loads()で辞書型に変換後、['ip']でIPアドレスを取得します。
  2. DynamoDBテーブル名の変更:
    • YourDynamoDBTableNameの部分を、実際のDynamoDBテーブル名に置き換えてください。
  3. DynamoDBのパーティションキーの変更:
    • idの値を、実際のDynamoDBのパーティションキーの値に変更してください。
  4. blynkAuthToken のURLエンコード:
    • 既報のLambda関数では出なかったエラーメッセージ TypeError [ERR_UNESCAPED_CHARACTERS]: Request path contains unescaped characters が発生しました。これは、HTTPリクエストのパスに問題があることが明確です。
    • blynkAuthTokenの値を encodeURIComponent() でエンコード して対策しました。

既報(DynamoDBに保存したIPアドレスをLambda関数で呼び出す)で作成したLambda関数を元にして、Lambda関数URLを使うための変更を加えたコードを示します。AWS上では新たに作成したコードで、元コードを上書きして使います。(バージョンアップデート)

'use strict';

const AWS = require('aws-sdk');
const dynamoDb = new AWS.DynamoDB.DocumentClient();
const tableName = 'IPTable'; // DynamoDBのテーブル名
const http = require('http');

// --------------- Helpers that build all of the responses -----------------------

function buildSpeechletResponse(title, output, repromptText, shouldEndSession) {
    return {
        outputSpeech: {
            type: 'PlainText',
            text: output,
        },
        card: {
            type: 'Simple',
            title: `SessionSpeechlet - ${title}`,
            content: `SessionSpeechlet - ${output}`,
        },
        reprompt: {
            outputSpeech: {
                type: 'PlainText',
                text: repromptText,
            },
        },
        shouldEndSession,
    };
}

function buildResponse(sessionAttributes, speechletResponse) {
    return {
        version: '1.0',
        sessionAttributes,
        response: speechletResponse,
    };
}

// --------------- Functions that control the skill's behavior -----------------------

function getWelcomeResponse(callback) {
    const sessionAttributes = {};
    const cardTitle = 'Welcome';
    const speechOutput = "二階の温度を教えてなどと問いかけると、それを答えます。";
    const repromptText = "私はこの部屋を見てるわよっ!何が知りたいのっ!   ってかっ";
    const shouldEndSession = false;

    callback(sessionAttributes,
        buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
}

function handleSessionEndRequest(callback) {
    const cardTitle = 'Session Ended';
    const speechOutput = 'Thank you for trying the Alexa Skills Kit sample. Have a nice day!';
    const shouldEndSession = true;

    callback({}, buildSpeechletResponse(cardTitle, speechOutput, null, shouldEndSession));
}

function createLocationAttributes(location) {
    return { location };
}

async function readTemperatureInSession(intent, session, callback) {
    const cardTitle = intent.name;
    const LocationSlot = intent.slots.Location;
    const MeasurementSlot = intent.slots.Measurement;
    let repromptText = '';
    let sessionAttributes = session.attributes || {};
    const shouldEndSession = false;
    let speechOutput = '';
    let body = '';
    const blynkport = '8080';
    let blynkAuthToken;
    let blynkPin;

    let location = LocationSlot.value || sessionAttributes.location || '二階';
    sessionAttributes.location = location;

    let ip;

    try {
        // DynamoDBからIPアドレスを取得
        const params = {
            TableName: tableName,
            Key: {
                id: 'globalIP' // パーティションキーは固定値
            }
        };
        const data = await dynamoDb.get(params).promise();
        const item = data.Item;

        if (!item || !item.ipAddress) {
            console.error('IPアドレスがDynamoDBに存在しません。');
            speechOutput = 'IPアドレスが取得できませんでした。';
            repromptText = 'もう一度お試しください。';
            callback(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
            return;
        }

        ip = item.ipAddress; // DynamoDBから取得したIPアドレス

    } catch (error) {
        console.error(`DynamoDBからIPアドレスを取得中にエラーが発生しました: ${error}`);
        speechOutput = 'IPアドレスの取得中にエラーが発生しました。';
        repromptText = 'もう一度お試しください。';
        callback(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
        return; // エラー発生時は処理を中断
    }

    switch (location) {
        case '二階':
            blynkAuthToken = encodeURIComponent('********************************');
            break;
        case '仏間':
            blynkAuthToken = encodeURIComponent('********************************');
            break;
        case '屋根裏':
            blynkAuthToken = encodeURIComponent('********************************');
            break;
        default:
            speechOutput = '指定された場所が見つかりませんでした。';
            repromptText = '他の場所を指定してください。';
            callback(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
            return;
    }

    let measurement = MeasurementSlot.value || '温度';
    switch (measurement) {
        case '何度':
        case '気温':
        case '室温':
        case '温度':
            blynkPin = 'V0';
            break;
        case '湿気':
        case '湿度':
            blynkPin = 'V1';
            break;
        case '大気圧':
        case '気圧':
            blynkPin = 'V2';
            break;
        case '熱中度指数':
        case '熱中度':
        case '暑さ指数':
        case '暑さ度':
        case '暑さ':
            blynkPin = 'V4';
            break;
        default:
            speechOutput = '指定された測定項目が見つかりませんでした。';
            repromptText = '他の測定項目を指定してください。';
            callback(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
            return;
    }

    try {
        console.log(`Sending request to Blynk server with Auth Token: ${blynkAuthToken}, Pin: ${blynkPin}, IP: ${ip}`);

        const httpPromise = new Promise((resolve, reject) => {
            http.get({
                host: ip,
                path: `/${encodeURIComponent(blynkAuthToken)}/get/${blynkPin}`,
                port: blynkport,
            }, (response) => {
                response.on('data', (d) => {
                    body += d;
                });
                response.on('end', () => {
                    resolve('Done Sending');
                });
            }).on('error', (e) => {
                reject(e); // エラーをreject
                console.error(`Blynkサーバーへのリクエストエラー: ${e}`); // エラーログ
            });
        });

        await httpPromise;

        console.log(`Received response from Blynk server: ${body}`);

        let info;
        try {
            info = parseFloat(JSON.parse(body)); // パースを試みる
        } catch (parseError) {
            console.error(`JSONパースエラー: ${parseError}, body: ${body}`);
            info = NaN; // パースに失敗したらNaNを設定
        }

        if (isNaN(info)) {
            speechOutput = '温度の取得に失敗しました。';
            repromptText = 'もう一度お試しください。';
            callback(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
        } else {
            // ... (温度表示処理)
            speechOutput = location + 'の ' + measurement + 'は ';
            repromptText = speechOutput;
            switch (measurement) {
                default:
                case '何度':
                case '気温':
                case '室温':
                case '温度':
                    speechOutput += `${info.toFixed(1)}度 です。`;
                    repromptText += `${info.toFixed(1)}℃です。`;
                    break;
                case '湿気':
                case '湿度':
                    speechOutput += `${info.toFixed(1)}パーセント です。`;
                    repromptText += `${info.toFixed(1)}%です。`;
                    break;
                case '大気圧':
                case '気圧':
                    speechOutput += `${info.toFixed(0)}ヘクトパスカル です。`;
                    repromptText += `${info.toFixed(0)}hPaです。`;
                    break;
                case '熱中度指数':
                case '熱中度':
                case '暑さ指数':
                case '暑さ度':
                case '暑さ':
                    let annotation = '';
                    if (info >= 31) {
                        annotation = '危険! ブラックです。';
                    } else if (info >= 28) {
                        annotation = '厳重警戒! レッドです。';
                    } else if (info >= 25) {
                        annotation = '警戒! オレンジです。';
                    } else if (info >= 21) {
                        annotation = '注意です。';
                    }
                    speechOutput += `${info.toFixed(0)}度 です。${annotation}`;
                    repromptText += `${info.toFixed(0)}℃です。${annotation}`;
                    break;
            }
            callback(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
        }

    } catch (error) {
        console.error(`温度取得処理全体のエラー: ${error}`);
        speechOutput = '温度の取得中にエラーが発生しました。';
        repromptText = 'もう一度お試しください。';
        callback(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
    }
}

// ... (onSessionStarted, onLaunch, onIntent, onSessionEnded関数は変更なし)
function onSessionStarted(sessionStartedRequest, session) {
    console.log(`onSessionStarted requestId=${sessionStartedRequest.requestId}, sessionId=${session.sessionId}`);
}

function onLaunch(launchRequest, session, callback) {
    console.log(`onLaunch requestId=${launchRequest.requestId}, sessionId=${session.sessionId}`);
    getWelcomeResponse((sessionAttributes, speechletResponse) => {
        callback(sessionAttributes, speechletResponse);
    });
}

function onIntent(intentRequest, session, callback) {
    console.log(`onIntent requestId=${intentRequest.requestId}, sessionId=${session.sessionId}`);
    const intent = intentRequest.intent;
    const intentName = intentRequest.intent.name;

    if (intentName === 'GetMeasurement') {
        readTemperatureInSession(intent, session, callback);
    } else if (intentName === 'AMAZON.HelpIntent') {
        getWelcomeResponse((sessionAttributes, speechletResponse) => {
            callback(sessionAttributes, speechletResponse);
        });
    } else if (intentName === 'AMAZON.StopIntent' || intentName === 'AMAZON.CancelIntent') {
        handleSessionEndRequest((sessionAttributes, speechletResponse) => {
            callback(sessionAttributes, speechletResponse);
        });
    } else {
        throw new Error('Invalid intent');
    }
}

function onSessionEnded(sessionEndedRequest, session) {
    console.log(`onSessionEnded requestId=${sessionEndedRequest.requestId}, sessionId=${session.sessionId}`);
    // callbackを呼び出す必要はありません。
    // context.succeed()も不要です。
}

exports.handler = (event, context) => {
    try {
        console.log('Event:', JSON.stringify(event));

        let globalIP;
        if (event.session && event.session.attributes && event.session.attributes.globalIP) {
            globalIP = event.session.attributes.globalIP;
            console.log(`Using globalIP from session attributes: ${globalIP}`);
            continueProcessing(event, context); // IPアドレス取得後に実行したい処理
        } else {
            console.log("globalIP not found in session attributes. Retrieving from DynamoDB or IP");
            // IPアドレスの取得処理 (DynamoDB or event.ip)
            if (event.body && JSON.parse(event.body).ip) { // Lambda関数URLからのIPアドレス取得
                globalIP = JSON.parse(event.body).ip;
                if (!event.session) {
                    event.session = {};
                }
                if (!event.session.attributes) {
                    event.session.attributes = {};
                }
                event.session.attributes.globalIP = globalIP; // セッション属性に保存
                console.log(`IP from event body: ${globalIP}`);
                updateIPAddress(event, context); // IPアドレス更新処理
            } else {
                getIPAddressFromDynamoDB(event, context);
            }
        }

    } catch (e) {
        console.error(`Exception: ${e}`);
        context.fail(`Exception: ${e}`);
    }
};

function updateIPAddress(event, context) {
    const params = {
        TableName: tableName,
        Item: {
            id: 'globalIP',
            ipAddress: JSON.parse(event.body).ip // event.bodyからIPアドレスを取得
        }
    };

    dynamoDb.put(params).promise()
        .then(() => {
            console.log(`Successfully updated IP address in DynamoDB: ${JSON.parse(event.body).ip}`);
            if (!event.session) {
                event.session = {};
            }
            if (!event.session.attributes) {
                event.session.attributes = {};
            }
            event.session.attributes.globalIP = JSON.parse(event.body).ip;
            console.log(`Updated globalIP to: ${JSON.parse(event.body).ip}`);
            continueProcessing(event, context);
        })
        .catch(err => {
            console.error(`Error updating IP address in DynamoDB: ${err}`);
            context.fail(`Error updating IP address: ${err}`);
        });
}

function getIPAddressFromDynamoDB(event, context) {
    const params = {
        TableName: tableName,
        Key: {
            id: 'globalIP'
        }
    };

    dynamoDb.get(params).promise()
        .then(data => {
            if (data.Item) {
                const ipAddress = data.Item.ipAddress;
                if (!event.session) {
                    event.session = {};
                }
                if (!event.session.attributes) {
                    event.session.attributes = {};
                }
                event.session.attributes.globalIP = ipAddress;
                console.log(`Retrieved IP address from DynamoDB: ${ipAddress}`);
                continueProcessing(event, context);
            } else {
                console.error('IP address not found in DynamoDB.');
                context.fail('IP address not found.');
            }
        })
        .catch(err => {
            console.error(`Error retrieving IP address from DynamoDB: ${err}`);
            context.fail(`Error retrieving IP address: ${err}`);
        });
}

function continueProcessing(event, context) {
    if (event.request && event.request.type) { // event.requestの存在チェックを追加
        // Alexaからのリクエストの場合の処理
        if (event.session && event.session.new) {
            onSessionStarted({ requestId: event.request.requestId }, event.session);
        }
        if (event.request.type === 'LaunchRequest') {
            onLaunch(event.request, event.session, (sessionAttributes, speechletResponse) => {
                context.succeed(buildResponse(sessionAttributes, speechletResponse));
                console.log('LaunchRequest succeeded');
            });
        } else if (event.request.type === 'IntentRequest') {
            onIntent(event.request, event.session, (sessionAttributes, speechletResponse) => {
                context.succeed(buildResponse(sessionAttributes, speechletResponse));
                console.log('IntentRequest succeeded');
            });
        } else if (event.request.type === 'SessionEndedRequest') {
            onSessionEnded(event.request, event.session);
            context.succeed();
            console.log('SessionEndedRequest succeeded');
        }
    } else {
        // Lambda URLからのリクエストの場合
        context.succeed(); // Lambda関数を正常終了
        console.log('Lambda URL request completed.');
    }
}

// ... (buildResponse, buildSpeechletResponseなどの関数は省略)
Python

まとめ: IPアドレスの優先順位:

プログラムは、IPアドレスを取得する際に、以下の優先順位で処理を行います。

順位1. セッション属性:
  • まず、以前の会話で保存された情報(セッション属性)の中にIPアドレスがないかを確認します。
  • もしセッション属性にIPアドレスがあれば、それを最優先で使用します。

順位2. 受け取ったIPアドレス:
  • セッション属性にIPアドレスがない場合、次に直接送られてきたIPアドレス(受け取ったIPアドレス)を使用します。
  • このIPアドレスは、データベースのIPアドレスを更新するために使用されます。

順位3. データベース(DynamoDB):
  • 受け取ったIPアドレスが使用された後に、そのIPアドレスでデータベースのIPアドレスを更新します。
  • これは、次回のIPアドレス取得のために使用されます。

Powered by Blogger | Designed by QooQ

keyboard_double_arrow_down

keyboard_double_arrow_down