Alexa技能部署至Cloud Functions时含额外属性JSON请求被拒
问题根因
报错和ask-sdk-core版本更新无关,核心是签名校验的入参处理逻辑不符合Alexa的验签规则:
- Alexa签名校验要求必须使用HTTP请求的原始未修改payload做哈希比对,任何对请求体的重新序列化、字段顺序调整、内容改动都会导致签名不匹配
- 你当前代码没有获取原始请求体,而是将express解析后生成的JS对象
req.body通过JSON.stringify重新序列化作为验签入参 - JSON标准不约束对象键的排序规则,当Alexa在请求中新增属性、或express解析后键顺序和原始请求不一致时,重新生成的序列化字符串和Alexa侧用来生成签名的原始文本完全不同,就会抛出
request body and signature does not match错误 - 其他同代码服务器可正常运行属于偶发兼容:老版本express/body-parser的序列化键顺序刚好和原始请求一致,不代表逻辑正确,遇到新增字段就会触发故障。
修复方案
核心是在express解析请求体时保留原始raw body,验签直接使用原始body,不要自行序列化。
代码调整
修改server.js
配置express的json解析中间件,在解析的同时缓存原始请求buffer:
const skillRoute = require("./skill"); const express = require("express"); const server = express(); // 解析JSON请求体,同时保留原始raw body用于验签 server.use(express.json({ verify: (req, res, buf, encoding) => { req.rawBody = buf; } })); server.use("/", skillRoute); exports.server = functions.https.onRequest(server);
修改skill.js
将验签逻辑的入参替换为缓存的原始请求体,移除手动序列化的逻辑:
// imports here... Router.post("/:locale", async (req, res) => { try { // 直接使用原始请求buffer做验签 await new SkillRequestSignatureVerifier().verify(req.rawBody, req.headers); await new TimestampVerifier().verify(req.rawBody); } catch (err) { console.log(`Error with message: ${err.message}`); console.log(`Error object: ${JSON.stringify(err)}`); return res.status(400).send(err.message); } const responseASK = await skill.invoke(req.body); return res.status(200).send(responseASK); }); module.exports = Router;
合规验证说明
修改完成后,无论Alexa后续在请求JSON中新增多少未知属性,验签使用的都是和Alexa侧完全一致的原始请求文本,不会再触发签名错误;同时ASK SDK本身默认支持忽略未知JSON属性,完全满足Alexa技能发布的向后兼容性要求。
内容的提问来源于stack exchange,提问作者Exlley Santos
相关产品推荐
相关产品推荐

