使用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
相关产品推荐
相关产品推荐

