Express服务处理AWS SNS订阅确认消息出现异常如何解决?
问题原因与修复方案
错误根因说明
- 触发
SyntaxError: Unexpected token u in JSON at position 0的原因:- 代码存在笔误:
let valueStr = req.bod遗漏了末尾的字母y,实际取值为undefined - 你已经配置了
app.use(express.json())中间件,AWS SNS发送的JSON请求体已经被自动解析为JavaScript对象挂载在req.body上,无需手动调用JSON.parse。对undefined执行JSON.parse会先将其转为字符串"undefined",首字符u直接触发语法解析错误
- 代码存在笔误:
- 触发
ERR_HTTP_HEADERS_SENT: Cannot set headers after they are sent to the client的原因:
当逻辑进入catch块时,已经执行res.status(500).send('Oops')完成了响应返回,catch块执行结束后仍会执行函数末尾的res.send('Ok'),同一请求重复返回响应会触发该错误 - 触发
UnhandledPromiseRejectionWarning的原因:- 你使用的
request库是回调风格API,原生不支持Promise,await request()不会等待回调执行就会继续向下运行,回调函数handleSubscriptionResponse中抛出的错误不在外层try/catch的捕获范围内,会变成未捕获的异步异常 - 回调函数中的
&&是HTML转义后的字符,实际运行时需要改为&&才能正常执行逻辑判断
- 你使用的
修复后的代码
这里替换已废弃的request库为支持Promise的axios,修正所有逻辑问题:
'use strict'; const express = require('express') const axios = require('axios') const app = express() const port = 4000 app.use(express.json()) app.post('/', async function (req, res) { try { const payload = req.body console.log(JSON.stringify(payload)) const messageType = req.header('x-amz-sns-message-type') if (messageType === 'SubscriptionConfirmation') { const url = payload.SubscribeURL; await axios.get(url) console.log('Yess! We have accepted the confirmation from AWS'); } else if (messageType === 'Notification') { console.log(payload) // 此处添加业务处理逻辑 } else { throw new Error(`Invalid message type ${payload.Type}`); } res.send('Ok') } catch (err) { console.error(err) res.status(500).send('Oops') } }) app.listen(port, () => { console.log(`Example app listening at http://localhost:${port}`) })
额外注意事项
- 运行前需要先安装axios依赖:
npm install axios - 确保你的ngrok公网地址配置到了SNS订阅的HTTP端点中,且安全组/防火墙放行4000端口的入站请求
内容的提问来源于stack exchange,提问作者Ahmad
相关产品推荐
相关产品推荐

