Lambda函数调用API发送OTP时遇TypeError [ERR_UNESCAPED_CHARACTERS]错误
修复Lambda调用API发送OTP时的路径转义错误
问题场景
在Lambda函数中调用第三方API发送OTP,通过请求路径的查询参数传递手机号和验证码,运行时报错:TypeError [ERR_UNESCAPED_CHARACTERS]: Request path contains unescaped characters
原代码如下:
const https = require('https'); function postRequest(body) { const ans = body.answer const phon = body.phone const options = { hostname: 'app.xxx.xx', path: '/api/v1/send?user_id=24xxx&api_key=3Yxxxx&sender_id=dEMO&to='+{phon}+'&message=Your%OTP%is%'+{ans}+'thanks', method: 'POST', port: 443, }; return new Promise((resolve, reject) => { const req = https.request(options, res => { let rawData = ''; res.on('data', chunk => { rawData += chunk; }); res.on('end', () => { try { resolve(JSON.parse(rawData)); } catch (err) { reject(new Error(err)); } }); }); req.on('error', err => { reject(new Error(err)); }); req.write(JSON.stringify(body)); req.end(); }); } exports.handler = async (event, context, callback) => { //Create a random number for otp const challengeAnswer = Math.random().toString(10).substr(2, 4); const phoneNumber = event.request.userAttributes.phone_number; console.log(event, context); await postRequest({ phone: phoneNumber, answer: challengeAnswer, }, function(err, data) { if (err) { console.log(err.stack); console.log(data); return; } console.log(`SMS sent to ${phoneNumber} and otp = ${challengeAnswer}`); return data; }); callback(null, event); };
错误原因
- 路径拼接语法错误:
+{phon}+和+{ans}+的写法错误,大括号会把变量转成[object Object]字符串,导致路径包含非法字符 - 查询参数未URL编码:手机号(可能带
+号)、验证码这类动态值直接拼接进路径,未进行URL编码,触发转义错误 - 冗余的POST请求体:API参数已通过查询参数传递,不需要再写入请求体,多余的
req.write可能造成不必要的问题 - async/await使用错误:
postRequest返回Promise,但调用时同时用了await和回调函数,属于混用,会导致逻辑混乱
修复方案
修正步骤
- 移除变量拼接时的大括号,直接用
+ phon +这类正确的字符串拼接方式 - 用
encodeURIComponent()对所有动态查询参数值进行URL编码 - 删除
req.write(JSON.stringify(body)),因为参数已在路径中传递 - 用
try/catch替代回调函数处理Promise的成功/失败逻辑
修正后的完整代码
const https = require('https'); function postRequest(body) { const ans = body.answer; const phon = body.phone; // 对动态参数进行URL编码,避免未转义字符 const encodedPhone = encodeURIComponent(phon); const encodedOtp = encodeURIComponent(ans); // 用模板字符串拼接路径,修正语法错误 const options = { hostname: 'app.xxx.xx', path: `/api/v1/send?user_id=24xxx&api_key=3Yxxxx&sender_id=dEMO&to=${encodedPhone}&message=Your%20OTP%20is%20${encodedOtp}%20thanks`, method: 'POST', port: 443, }; return new Promise((resolve, reject) => { const req = https.request(options, res => { let rawData = ''; res.on('data', chunk => { rawData += chunk; }); res.on('end', () => { try { resolve(JSON.parse(rawData)); } catch (err) { reject(new Error(err)); } }); }); req.on('error', err => { reject(new Error(err)); }); // 移除不必要的请求体写入 req.end(); }); } exports.handler = async (event, context, callback) => { const challengeAnswer = Math.random().toString(10).substr(2, 4); const phoneNumber = event.request.userAttributes.phone_number; console.log(event, context); try { const data = await postRequest({ phone: phoneNumber, answer: challengeAnswer, }); console.log(`SMS sent to ${phoneNumber} and otp = ${challengeAnswer}`); } catch (err) { console.log(err.stack); } callback(null, event); };
额外说明
encodeURIComponent()会对所有非URL安全字符进行转义,比如空格转成%20、+号转成%2B,完全符合URL规范- 路径中的
%OTP%改成了%20OTP%20,原写法会被解析为非法的URL编码,正确的空格转义是%20 - 用模板字符串拼接路径比
+号更易读,也减少拼接错误的概率
内容的提问来源于stack exchange,提问作者hewa
相关产品推荐
相关产品推荐

