You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Alexa Skills Kit调用API渲染APL无数据显示问题排查

问题描述

使用Alexa Skills Kit从API获取包含name、id、imgurl的分类数据及对应视频数据,设计APL页面展示分类名称与图片时,调用API数据无内容显示,预览仅出现一个点;但硬编码数据可正常展示。

现有代码

APL代码

{
  "type": "APL",
  "version": "1.6",
  "mainTemplate": {
    "items": [
      {
        "type": "Pager",
        "id": "myPager",
        "data": "${payload.imageListData.listItems}",
        "navigation": "wrap",
        "items": {
          "type": "Container",
          "items": [
            {
              "type": "Image",
              "source": "${data.imageSource}",
              "scale": "best-fill",
              "width": "100%",
              "height": "100%"
            },
            {
              "type": "Text",
              "text": "${ordinal(data.index + 1)}. ${data.primaryText}",
              "fontSize": "20dp",
              "color": "white",
              "position": "absolute",
              "bottom": "10%",
              "left": "5%"
            }
          ]
        }
      }
    ]
  }
}

index.js代码

/* *
 * This sample demonstrates handling intents from an Alexa skill using the Alexa Skills Kit SDK (v2).
 * */
const api = require('./api.js');
const Alexa = require("ask-sdk-core");
const Country = require('./country.js');
const DOCUMENT_ID = "carousel";
const fetchData = async () => {
    return await api.getAllCountry();
}
const createDirectivePayload = (aplDocumentId, dataSources = {}, tokenId = "documentToken") => {
    return {
        type: "Alexa.Presentation.APL.RenderDocument",
        token: tokenId,
        document: {
            type: "Link",
            src: "doc://alexa/apl/documents/" + aplDocumentId
        },
        datasources: dataSources
    }
};

const updateCategories = (handlerInput, categories) => {
    const directive = {
        type: 'Dialog.UpdateDynamicEntities',
        updateBehavior: 'REPLACE',
        types: [
            {
                name: 'Categories',
                values: categories.map(category => ({ id: category.primaryText, name: { value: category.primaryText } }))
            }
        ]
    };
    handlerInput.responseBuilder.addDirective(directive);
};

const SampleAPLRequestHandler = {
    canHandle(handlerInput) {
        return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
            && Alexa.getIntentName(handlerInput.requestEnvelope) === 'category';
    },
    async handle(handlerInput) {
        const countryData = await fetchData();
        const datasource = {
            "imageListData": {
                "type": "object",
                "objectId": "imageListSample",
                "backgroundImage": {
                    "contentDescription": null,
                    "smallSourceUrl": null,
                    "largeSourceUrl": null,
                    "sources": [
                        {
                            "url": "",
                            "size": "large"
                        }
                    ]
                },
                "title": "Categorías",
                "listItems": countryData.map(country => ({
                    'primaryText': country.name,
                    'imageSource': country.image_url,
                })),
                "logoUrl": "",
                "hintText": "Prueba: \"Alexa, selecciona el número 1\""
            }
        }
        updateCategories(handlerInput, datasource.listItems);
        if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) {
            const aplDirective = createDirectivePayload(DOCUMENT_ID, datasource);
            handlerInput.responseBuilder.addDirective(aplDirective);
        }
        return handlerInput.responseBuilder.getResponse();
    }
};

exports.handler = Alexa.SkillBuilders.custom()
    .addRequestHandlers(SampleAPLRequestHandler)
    .lambda();

排查与修复方案

1. 增加API调用错误处理

当前fetchData未处理API请求失败的情况,若API报错会导致countryData为undefined,后续map操作直接报错,导致APL无数据。修改后:

const fetchData = async () => {
    try {
        return await api.getAllCountry();
    } catch (error) {
        console.error('API请求失败:', error);
        return []; // 返回空数组避免后续逻辑崩溃
    }
}

2. 校验数据有效性

在handle函数中先校验countryData是否有效,避免空数据进入后续流程:

async handle(handlerInput) {
    const countryData = await fetchData();
    // 无数据时直接返回语音提示
    if (!countryData || countryData.length === 0) {
        return handlerInput.responseBuilder
            .speak('暂时没有分类数据,请稍后再试')
            .getResponse();
    }
    // 后续原有逻辑...
}

3. 处理动态实体更新的边界情况

仅当数据有效时才更新动态实体,避免空数组导致的实体更新错误:

// 替换原有updateCategories调用
if (datasource.listItems.length > 0) {
    updateCategories(handlerInput, datasource.listItems);
}

4. 字段安全处理

对API返回的图片URL做默认值处理,避免空URL导致图片加载失败:

listItems: countryData.map(country => ({
    'primaryText': country.name || '未命名分类',
    'imageSource': country.image_url || '',
})),

5. 日志排查辅助

在handle函数中添加日志,确认API返回数据结构是否符合预期:

console.log('API返回原始数据:', countryData);
console.log('生成的数据源:', datasource);

修正后的核心代码片段

const fetchData = async () => {
    try {
        return await api.getAllCountry();
    } catch (error) {
        console.error('API请求失败:', error);
        return [];
    }
}

const SampleAPLRequestHandler = {
    canHandle(handlerInput) {
        return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
            && Alexa.getIntentName(handlerInput.requestEnvelope) === 'category';
    },
    async handle(handlerInput) {
        const countryData = await fetchData();
        if (!countryData || countryData.length === 0) {
            return handlerInput.responseBuilder
                .speak('暂时没有分类数据,请稍后再试')
                .getResponse();
        }
        console.log('API返回数据:', countryData);
        const datasource = {
            "imageListData": {
                "type": "object",
                "objectId": "imageListSample",
                "backgroundImage": {
                    "contentDescription": null,
                    "smallSourceUrl": null,
                    "largeSourceUrl": null,
                    "sources": [
                        {
                            "url": "",
                            "size": "large"
                        }
                    ]
                },
                "title": "分类",
                "listItems": countryData.map(country => ({
                    'primaryText': country.name || '未命名分类',
                    'imageSource': country.image_url || '',
                })),
                "logoUrl": "",
                "hintText": "试试:“Alexa,选择第1个”"
            }
        }
        if (datasource.listItems.length > 0) {
            updateCategories(handlerInput, datasource.listItems);
        }
        if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) {
            const aplDirective = createDirectivePayload(DOCUMENT_ID, datasource);
            handlerInput.responseBuilder.addDirective(aplDirective);
        }
        return handlerInput.responseBuilder
            .speak('已为你展示分类列表')
            .getResponse();
    }
};

内容的提问来源于stack exchange,提问作者Darkhaiass

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 16:34:52