WSL起个服务,localhost访问嘛报错 connect ECONNREFUSED

开始以为是apipost的问题,postman也好浏览器也好都能访问,然后就apipost不行。

这边的同学用远程协助之后,我观察到apipost的log里面,localhost解析出来是127.0.0.1,但是我自己去控制台ping,解析出来是[::1] (win vista之后的默认)。

侧面说明了这127.0.0.1不是解析出来的,是代码里面写死的(code review?)。

这个么好办了,既然解析出来的 loopback address是IPV6的,那么我们直接用。

浏览器访问没问题,怀着高兴的心情去用,搞笑的是apipost不支持V6的地址,直接给我parse成http字符了。

好了只能另寻出路,查啊查,研究了一下WSL的网络(搞了n年linux现在来研究windows。。。),发现这货不是绑定到localhost的。

WSL2的虚拟机自己有个虚拟的NIC,你可以理解为localhost作为一个NAT网关,直接转发到下面设置好端口转发的wsl虚拟网卡上面。

想研究深入的自己看文档:https://docs.microsoft.com/en-us/windows/wsl/

这样么挺好,我们找到wsl自己的ip就好了,进wsl

~ ip -4 addr show eth0
5: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    inet 172.17.118.219/20 brd 172.17.127.255 scope global eth0
       valid_lft forever preferred_lft forever

这样这个东西 172.17.118.219, 就是wsl的ip,这个可以直接放到apipost的环境里面去用,没有任何问题。

问题解决。

但是呢,wsl这东西每次启动都会换ip,很烦,怎么办,写个powershell脚本,等每次wsl启动完了跑一下,把这ip写到一个固定的host上面就好了 (所谓本地DDNS)

$hostname = "wsl"

# find ip of eth0
$ifconfig = (wsl -- ip -4 addr show eth0)
$ipPattern = "((\d+\.?){4})"
$ip = ([regex]"inet $ipPattern").Match($ifconfig).Groups[1].Value
if (-not $ip) {
    exit
}
Write-Host $ip

$hostsPath = "$env:windir/system32/drivers/etc/hosts"

$hosts = (Get-Content -Path $hostsPath -Raw -ErrorAction Ignore)
if ($null -eq $hosts) {
    $hosts = ""
}
$hosts = $hosts.Trim()

# update or add wsl ip
$find = "$ipPattern\s+$hostname"
$entry = "$ip $hostname"

if ($hosts -match $find) {
    $hosts = $hosts -replace $find, $entry
}
else {
    $hosts = "$hosts`n$entry".Trim()
}

try {
    $temp = "$hostsPath.new"
    New-Item -Path $temp -ItemType File -Force | Out-Null
    Set-Content -Path $temp $hosts

    Move-Item -Path $temp -Destination $hostsPath -Force
}
catch {
    Write-Error "cannot update wsl ip"
}

脚本抄来的,写得很不错没必要自己改,原文在这里:https://abdus.dev/posts/fixing-wsl2-localhost-access-issue/,设置自动trigger这些都有。

本来想发到apipost自己论坛去的,给我报什么非法字符,也是无奈啊