在调试商户转账到零钱接口的过程中,收到了一个报错:
{ 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 白名单,果然我一配置就成功了,前前后后绕了一大圈,在大年初一花了好几个小时。