AWS Lambda POST 请求返回 404 Error
结论
这个 404 是 USIO 服务器返回的 HTTP 响应,与 Lambda 或 VPC 网络故障无关。Lambda 已成功连接到 api.securepds.com,但服务器没有找到与当前请求匹配的接口。
代码中有两个明确的问题:
Content-Type被写成了https://application/json,正确值是application/json。obj已经是 JSON 字符串,doPostRequest()又对它执行了一次JSON.stringify(),导致请求体被二次序列化。
当前代码还只记录了状态码,没有读取响应体。服务器解释 404 原因的错误信息很可能就在响应体中。
修正请求头和请求数据
不要手工拼接 JSON 字符串,直接构造 JavaScript 对象:
const obj = {
MerchantID: merchantId,
Login: merchantLogin,
Password: merchantPassword,
Token: token,
Amount: result.Items[i].amount
};
只在发送请求时调用一次 JSON.stringify()。
还应删除 Access-Control-Allow-Origin。这是服务器返回给浏览器的 CORS 响应头,Lambda 发起服务器端请求时不需要携带它。
推荐实现
const https = require('https');
const doPostRequest = (data) => {
return new Promise((resolve, reject) => {
const body = JSON.stringify(data);
const options = {
hostname: 'api.securepds.com',
port: 443,
path: '/2.0/payments.svc/JSON/SubmitTokenPayment',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(body),
'Accept': 'application/json'
}
};
const req = https.request(options, (res) => {
res.setEncoding('utf8');
let responseBody = '';
res.on('data', (chunk) => {
responseBody += chunk;
});
res.on('end', () => {
resolve({
statusCode: res.statusCode,
headers: res.headers,
body: responseBody
});
});
});
req.on('error', (error) => {
reject(error);
});
req.write(body);
req.end();
});
};
调用时:
try {
const response = await doPostRequest(obj);
console.log('Status code:', response.statusCode);
console.log('Response headers:', JSON.stringify(response.headers));
console.log('Response body:', response.body);
if (response.statusCode < 200 || response.statusCode >= 300) {
throw new Error(
`USIO request failed with status ${response.statusCode}: ${response.body}`
);
}
} catch (error) {
console.error('Error sending USIO payment request:', error);
}
为什么原请求体可能不正确
原代码使用模板字符串构造 obj:
const obj = `{"MerchantID":"...",
"Login":"...",
"Password":"...",
"Token":"...",
"Amount":"..."}`;
此时 obj 已经是字符串。如果再次执行:
JSON.stringify(obj)
发送的内容会类似:
"{\"MerchantID\":\"...\",\"Login\":\"...\"}"
外层多了一对引号。服务器收到的是一个包含 JSON 文本的字符串,而不是 JSON object。
如果必须保留字符串形式,发送时就不要再次序列化:
req.write(data);
不过,直接构造对象更安全,也能避免括号遗漏、引号转义错误以及特殊字符破坏 JSON。问题中的示例字符串没有显示结尾的 }。如果实际代码同样缺少这个括号,请求体就是无效 JSON。
如果修正后仍然返回 404
读取完整响应体,并继续检查以下项目:
- USIO 提供的生产环境或测试环境 hostname 是否确实为
api.securepds.com。 - 接口路径、大小写和版本号是否完全一致:
/2.0/payments.svc/JSON/SubmitTokenPayment。 - 该 endpoint 是否接受
POST,接口文档是否要求提供其他认证头。 - 响应中的
Locationheader 是否指向另一个地址。 - 使用相同的 hostname、path、headers 和 body 在 Postman 或
curl中测试,判断问题来自接口配置还是代码。
例如:
curl -i \
-X POST \
'https://api.securepds.com/2.0/payments.svc/JSON/SubmitTokenPayment' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
--data '{
"MerchantID": "REDACTED",
"Login": "REDACTED",
"Password": "REDACTED",
"Token": "REDACTED",
"Amount": "10.00"
}'
如果 curl 使用相同内容仍然返回 404,问题出在 endpoint、环境或 USIO 侧的路由要求,而不是 Lambda。
注意事项
不要在日志中打印完整的 payment payload、密码或 payment token。调试时应隐藏敏感字段:
console.log({
MerchantID: merchantId,
Login: merchantLogin,
Password: '[REDACTED]',
Token: '[REDACTED]',
Amount: result.Items[i].amount
});
未配置 VPC 的 Lambda 通常可以通过默认公网出口访问外部 HTTPS API。网络不可达时,常见表现是超时、DNS 错误或连接错误,而不是由对方服务器返回有效的 404 响应。
备注:内容仅供参考。
