在调试商户转账到零钱接口的过程中,收到了一个报错:
{ code: 'INVALID_REQUEST', message: '此IP地址不允许调用该接口' }
很明显是调用api 的ip 需要添加白名单,但遗憾的是,我们添加白名单之后,仍然一直报这个错误。
后来我用postman 模拟接口的时候发现能成功,但nodejs 请求就一直失败。
推测可能是nodejs 请求的时候,走了ipv6 的网络,ipv6 白名单并没有配置。于是让超级管理员帮忙配置ipv6 白名单,结果他说报错,配置不成功,只能吐槽微信支持太差。
为了验证猜想,我把mac 电脑的ipv6 网络禁用掉,果然请求成功了。
sudo networksetup -setv6off Wi-Fi // 禁用WiFi ipv6 sudo networksetup -setv6automatic Wi-Fi // 重启ipv6
因为我们的服务在苹果商店上架,需要支持ipv6 网络,不能把整个ipv6 网络禁用掉,于是思考能否只对这个请求,强制使用ipv4。
但经过查资料,fetch、axios 都不支持配置限制网络为ipv4。
但查到nodejs 的http 模块可以指定只走ipv4。Node.js 内置的 http 和 https 模块也允许你发起网络请求。你可以使用这些模块手动创建请求,并通过设置 family 选项来限制使用 IPv4。例如
const request = require('request');
const options = {
url: 'http://example.com',
family: 4, // Force IPv4
};
// 发起请求
request(options, (error, response, body) => {
if (error) {
console.error('Error occurred:', error);
} else {
console.log('Response:', body);
}
});
但遗憾的是,我封装之后,似乎并没有走ipv6, 问chatGPT 后说:
在Node.js中,设置family: 4确实应该限制请求只通过IPv4进行。如果你的代码设置了family: 4,但仍然似乎在使用IPv6,有几个可能的原因需要考虑:
- 操作系统支持IPv6优先级比较高:在某些操作系统中,默认情况下,如果有IPv6地址,系统会优先选择IPv6。这可能会导致即使设置了
family: 4,仍然使用IPv6。 - 网络环境:在某些网络环境下,即使你的机器只支持IPv4,但是它可能会通过IPv6代理进行网络请求。这种情况下,即使你的代码设置了
family: 4,但请求仍然可能通过IPv6网络。
于是我又考虑换一个方法,先通过dns 模块之间获取到ipv4 的地址,通过ip 访问就能保证是ipv4 网络了。
const dns = require('dns');
function resolveIPv4(hostname) {
return new Promise((resolve, reject) => {
dns.resolve4(hostname, (err, addresses) => {
if (err) {
reject(err);
} else {
resolve(addresses[0]); // 返回第一个IPv4地址
}
});
});
}
// 使用示例
const hostname = 'example.com';
resolveIPv4(hostname)
.then(ipv4 => {
console.log(`The IPv4 address of ${hostname} is: ${ipv4}`);
// 在这里可以使用该IPv4地址进行网络请求
})
.catch(err => {
console.error('Error occurred while resolving IPv4 address:', err);
});
但又坑了,ip 访问一直报错,怀疑微信支付可能有限制。
最后,找到nodejs 的一个dns 配置setDefaultResultOrder,可以优先使用ipv4 网络,这个配置用上之后,果然成功了。
dns.setDefaultResultOrder('ipv4first');但这里说的是优先,其实还是有一点不放心。
最后让超级管理员扫码,我登录后台看下,我认为应该可以配置ipv6 白名单,果然我一配置就成功了,前前后后绕了一大圈,在大年初一花了好几个小时。