API 连接与 IPv6

跟进:API connection via ipv6 vs. ipv4 - support - Discourse Meta

我最近将 Node.js 从 18 升级到 20,我的应用程序突然无法从 Discourse 获得 API 响应。花了我一些时间才弄清楚这与上述问题有关。我通过仅使用 IPv4 进行连接进行了验证,例如:

import {Agent} from 'node:https'
import axios from 'axios'
import {env} from 'node:process'
export const axiosDiscourse = axios.create({
  baseURL: 'https://<discourse-url>',
  headers: {
    'api-key': env['DISCOURSE_KEY'],
    'api-username': env['DISCOURSE_USERNAME']
  },
  httpsAgent: new Agent({
    family: 4
  })
})

重要的是指定 HTTP Agent——我之前没有使用它。现在可以工作了,但我正试图摆脱 Axios,这样我就可以使用其他基于 fetch 的库,如 Wretch(主要是为了通过在前端也使用它来减小包大小):[elbywan/wretch: A tiny wrapper built around fetch with an intuitive syntax. :candy: (github.com)](https://github.com/elbywan/wretch)。然而,fetch 没有指定 IPv4 或 IPv6 的选项。因此,我认为我需要:

  1. 强制仅使用 IPv4,尽管我迄今为止的所有尝试都未能成功。
  2. 与 Discourse 确认如何才能在 IPv6 上实现此功能。

我的应用程序正在连接到各种其他 API,没有一个出现此问题,只有与 Discourse 的连接失败了。

以防万一,这是我收到的错误:

Error: connect ETIMEDOUT 184.105.99.43:443
    at createConnectionError (node:net:1634:14)
    at Timeout.internalConnectMultipleTimeout (node:net:1685:38)
    at listOnTimeout (node:internal/timers:575:11)
    at processTimers (node:internal/timers:514:7) {
  errno: -110,
  code: 'ETIMEDOUT',
  syscall: 'connect',
  address: '184.105.99.43',
  port: 443
},
Error: connect ENETUNREACH 2602:fd3f:3:ff01::2b:443 - Local (:::0)
    at internalConnectMultiple (node:net:1176:40)
    at Timeout.internalConnectMultipleTimeout (node:net:1687:3)
    at listOnTimeout (node:internal/timers:575:11)
    at processTimers (node:internal/timers:514:7) {
  errno: -101,
  code: 'ENETUNREACH',
  syscall: 'connect',
  address: '2602:fd3f:3:ff01::2b',
  port: 443
}

有趣的是,与上面提到的帖子不同,我没有得到长时间的响应。我的请求立即因这个错误而失败。API 调用在浏览器、curl 和我可以测试的任何其他工具中都可以正常工作。

我向 API 发出请求的方式并不重要,只要我从我的应用程序发出请求即可。它就是会失败,并且只有在使用上面提到的 family 选项时才能工作。在链接的帖子中,我看到有人提到:

你需要调查为什么你的网络上的 IPv6 连接不起作用。

我对这两点有疑虑:

  1. 我不知道如何具体检查这一点。
  2. 不确定为什么这只会是 Discourse 的问题,而且只在我的应用程序中出现。
1 个赞

另外需要注意的是,这仅在我的WSL实例内部发生。如果我在宿主Windows设备上直接运行我的应用程序,它可以正常连接。

我知道这可能是我设置中的一个非常具体的问题,但我现在不知道该从哪里入手查找问题。任何提示都会有帮助!

1 个赞

您使用的库似乎同时尝试通过 IPv4 和 IPv6 进行连接;这是个好消息,意味着您没有遇到与此处相同的问题!

让我们分别处理它们:

这意味着您这边设置了一个 TCP SYN 来尝试连接到托管实例,但没有收到响应。这通常意味着以下情况之一:

  • 请求未到达服务器
  • 服务器(或路径上的某个设备)故意静默丢弃了它
  • 响应未返回到您的机器

由于

这很可能是您机器上网络设置的问题。

这意味着您的网络堆栈说“我无法到达那里”,这是没问题的,因为您显然会回退到 IPv4。

总而言之,我怀疑:

  • 从您的机器连接 IPv4 失败(尚不清楚这是否属实,请验证——“可以正常连接”可能意味着它正在使用 IPv4 或 IPv6)
  • 从您的 WSL 容器连接 IPv4 失败
  • 从您的机器连接 IPv6 正常
  • 从您的 WSL 容器连接 IPv6 失败

请向 @team 发送一条消息,告知您的外部 IPv4 地址,我们将检查它是否被故意丢弃——我们确实屏蔽了一些行为不端的 IP 范围,这将有助于我们排除这种情况。

但是,如果 IPv4 和 IPv6 都从您的机器连接正常,但从您的 WSL 容器连接失败,那么您需要解决 WSL 设置方面的问题。

非常感谢您的回复。

关于您的嫌疑,这是我到目前为止可以测试的内容:

  • 我尝试从 Windows 设置中禁用 IPv6:

根据我的理解,这应该只允许 IPv4 连接。如果可以,那就可以了。

  • 我尝试运行:
 curl -4 https://<host>/latest.json?order=created

从 WSL 运行,它运行正常(我收到了响应)。

  • 不确定如何仅测试 IPv6,因为一旦我像上面截图那样禁用 IPv4 而保留 IPv6,我的电脑基本上就断开了互联网连接——所有连接都失败了,这可以预料。

  • 我尝试运行:

 curl -6 https://<host>/latest.json?order=created -v
*   Trying 2602:fd3f:3:ff01::2b:443...
* Immediate connect fail for 2602:fd3f:3:ff01::2b: Network is unreachable
* Closing connection 0
curl: (7) Couldn't connect to server

从 WSL 运行,它立即失败了。

今天我在 WSL 上遇到了一些麻烦,所以我最终重新配置了一个全新的安装。这是一个全新的实例,只安装了 asdf 和 Node.js(并更新了所有系统软件包)。不确定这是否仍然与 WSL 端的一些错误配置有关——我现在应该使用所有默认设置。

我将我的公共 IPv4 地址分享给提到的组。

嗯,我还没看到发送私人消息的方法,可能是因为我是新用户。

更有趣的是……当我检查我的公共 IPv4 地址时,该网站还试图向我显示我的 IPv6 地址,并显示“未检测到 IPv6”。因此,我继续检查我是否根本没有 IPv6 连接,然后我找到了这个页面:如何在 TP-Link 无线路由器上设置 IPv6 服务

它显示路由器应该有一个专门的部分来使用 IPv6。我的路由器没有这个部分,而且我也找不到那里显示的 PPPoE v6 选项。所以也许我的路由器根本不支持 IPv6——这可能就是为什么 IPv6 连接失败的原因(也解释了为什么当我禁用 Windows 设置中的 IPv4 时,我基本上失去了互联网连接)。

编辑:我有这个路由器 TL-WR841N | 300Mbps 无线 N 路由器 | TP-Link 印度,它说支持 IPv6 :thinking:

编辑 2:但是使用类似 v6.testmyipv6.com 的东西会给我 ERR_NAME_NOT_RESOLVED,所以看起来 IPv6 确实对我不起作用。

如果这是问题所在,我仍然不知道为什么会突然开始发生这种情况。它已经正常工作了一段时间。

我已经给你稍微推了一下。 :slight_smile: 如果你现在点击 @team,你应该就能看到消息按钮了。 :+1:

1 个赞

好的,已发送!

1 个赞

附加数据点,我从使用 IPv6 的移动网络切换到了热点。我现在可以使用以下命令进行验证:

curl -6 https://<host>/latest.json?order=created -v
*   Trying 2602:fd3f:3:ff01::2b:443...
* Immediate connect fail for 2602:fd3f:3:ff01::2b: Network is unreachable
* Closing connection 0
curl: (7) Couldn't connect to server

仍然以类似的方式失败。但是,在 Windows 设置中禁用 IPv4 后,我可以访问互联网,这与之前不同。所以新的数据:

  • Windows 上的 IPv4:工作正常
  • Windows 上的 IPv6:工作正常
  • WSL 上的 IPv4:工作正常
  • WSL 上的 IPv6:失败

如果我不为 curl 指定 -4-6,它会回退到 IPv4(IPv6 立即失败):

curl https://<host>/latest.json?order=created -v
*   Trying 184.105.99.43:443...
*   Trying 2602:fd3f:3:ff01::2b:443...
* Immediate connect fail for 2602:fd3f:3:ff01::2b: Network is unreachable
* Connected to <host> (184.105.99.43) port 443 (#0)

我还运行了:

ping -6 google.com

从 Windows 和 WSL 运行。它在 Windows 上工作正常,在 WSL 上失败。我认为我现在有足够的信息和验证来证明我的 WSL 实例的 IPv6 连接出现了问题。看起来像是一个问题:无法访问仅 IPv6 地址 · Issue #4518 · microsoft/WSL (github.com)

终于!

根据上面链接的讨论,我能够在 .wslconfig 中添加

[experimental]
networkingMode=mirrored

这样我的 WSL 实例就获得了 IPv6 连接。我现在可以成功运行:

curl -6 https://<host>/latest.json?order=created

不过在我的 WiFi 上仍然无法工作,这很可能是因为这个旧路由器不支持 IPv6。在使用我手机的热点时,它可以正常工作。

非常感谢 @JammyDodger 的指导,你指明了正确的方向!

好的,看来在原始帖子和现在之间肯定发生了一些变化,因为您之前收到的是:

很高兴看到现在它能正常工作了。

是的,这仍然让我感到困惑。正如我之前提到的,我之前能够通过 WSL 发送 curl 请求并且可以正常工作。不知何故,在我的应用程序中使用 Axios 却失败了(也许是 Axios 或 Node.js 的问题?)。

不知何故,curl -4 仍然有效,并且在我指定 httpFamily 时 Axios 也有效,正如我在原始帖子中所示。但这并不是一个我会再为之烦恼的错误。

为了进行健全性检查,我回滚到了 Node.js 18,并且无需指定 httpFamily 即可连接,因此这肯定是在 Node.js 19 或 20 中发生了一些变化。但正因为如此,我至少了解了 IPv6 的问题,否则我仍然不会去搜索或了解它。

我也可以使用 bun 而不是 Node.js 来运行代码,而无需指定 IPv4 问题。我已经联系了 Node.js:https://github.com/orgs/nodejs/discussions/50826