你做了什么
终端里运行 php artisan serve --port=8120 和 npm run dev,然后浏览器输入 http://localhost:8120,页面出现了。
从零开始 · 由浅入深
从浏览器输入地址到看到页面的完整链路。每一层概念都在它第一次被用到的场景中解释, 不跳步, 不假设你已经知道。
终端里运行 php artisan serve --port=8120 和 npm run dev,然后浏览器输入 http://localhost:8120,页面出现了。
把这"一瞬间"拆开——从你敲下回车到看到页面的每一步,让你以后遇到端口不通、样式丢失、WSL2 连不上等问题时,能自己判断问题出在哪一层。
http(协议)说用什么语言交谈;localhost(主机名)说去哪台机器;8120(端口)说进哪个门。
http:// 默认 80,https:// 默认 443。不写端口时浏览器自动补上。
浏览器说"在吗?"→ 服务器说"在"→ 浏览器说"好,开始传"。连接建立后发 HTTP 请求。
一台电脑可以同时运行 MySQL (3306)、Redis (6379)、Laravel (8120,本文示例)、Vite (5173)。IP 找到机器,端口找到服务。类比:IP = 写字楼地址,端口 = 房间号。
源端口(操作系统随机分配)+ 目标端口(服务监听的)。多个浏览器标签可以同时访问同一服务——每个标签的源端口不同。
| 端口范围 | 名称 | 说明 | 举例 |
|---|---|---|---|
| 0 - 1023 | 知名端口 | 系统保留,绑定需管理员 | 80 (HTTP), 443 (HTTPS), 22 (SSH) |
| 1024 - 49151 | 注册端口 | 应用常用,无需管理员 | 3306 (MySQL), 6379 (Redis), 3000/5173 (开发) |
| 49152 - 65535 | 动态/私有 | 系统临时分配 | 浏览器发起连接时的源端口 |
程序是磁盘上的文件(如 php.exe),进程是加载到内存中运行起来的实例。食谱 vs 厨师炒菜。
进程调用 bind() 告诉操作系统:"我要在 127.0.0.1:8120 等连接"。此后操作系统代为处理 TCP 握手,把连接交给进程。
同一个端口同一时间只能被一个进程监听。启动第二个会报 EADDRINUSE。终端关了,服务就没了。
ss -ltnp | grep 8120;Windows → Get-NetTCPConnection -LocalPort 8120操作系统内核中的虚拟接口(Linux: lo,Windows: Loopback Pseudo)。数据包进入后立即返回,从不经过物理网卡。整个 127.x.x.x 网段都是回环地址。
只能在服务启动时作为监听地址使用,意思是"在所有网卡上监听"。不能作为浏览器访问地址——输入 http://0.0.0.0:8120 不会工作。
| 地址 | 含义 | 浏览器能访问? |
|---|---|---|
127.0.0.1 | 当前设备的回环地址 | ✅ 访问本机服务 |
localhost | 主机名,解析到 127.0.0.1 或 ::1 | ✅ 同上 |
0.0.0.0 | 绑定所有网卡(仅监听用) | ❌ 不是访问地址 |
192.168.x.x / 10.x.x.x / 172.16-31.x.x | 私有地址,局域网内使用 | ✅ 局域网内可访问 |
| 监听方式 | 命令示例 | 谁可以访问 |
|---|---|---|
127.0.0.1 | --host=127.0.0.1 | 只有本机 |
localhost | --host localhost | 解析到 127.0.0.1 或 ::1 |
0.0.0.0 | --host=0.0.0.0 | 本机、局域网、WSL2、Docker 全能 |
| 局域网 IP | --host 192.168.1.100 | 只有通过这个 IP 来的请求 |
传统:一个后端服务返回一切。
现代:后端返回 HTML + API,前端开发服务器返回 CSS/JS(支持 HMR 热更新)。
Hot Module Replacement:修改代码后浏览器自动更新,不刷新整个页面。Vite 通过 WebSocket(ws://localhost:5173)通知浏览器。WSL2 场景下 HMR 连接也可能受转发影响。
concurrently 一个命令同时启动 Laravel + Vite,Ctrl+C 一起关闭。不用开两个终端。不是一个简单模拟器,而是一个完整的 Linux 内核运行在 Hyper-V 虚拟机中。拥有独立的网络命名空间、独立的 IP 地址。
Docker Desktop + WSL2 后端 → 每个容器还有自己的网络命名空间。形成 Windows → WSL2 → Docker 三层"套娃"。
Windows、WSL2、Docker 各有独立的回环接口(lo)和独立的 127.0.0.1。它们天然隔离、互不干扰。
wslhost.exe 自动转发机制。wslhost.exe 充当了"接线员":它在 Windows 侧监听端口,通过 Hyper-V 的 VMBus 通道把流量隧道转发到 WSL2。整个过程对浏览器和应用完全透明。WSL2 有独立 IP (172.x.x.x),通过 Hyper-V NAT 上网。localhost 转发由 wslhost 实现。所有版本都支持。
Win11 22H2+。WSL2 与 Windows 共享 IP。通过 loopback0 接口中继。IPv6 和 VPN 兼容性更好。在 .wslconfig 中设置 networkingMode=mirrored。
Windows 和 WSL2 是独立的网络命名空间,端口资源不共享。Windows 的 6543 被占用,完全不影响 WSL2 内使用 6543。
wslhost.exe 需要在 Windows 的 127.0.0.1:6543 创建监听做转发。如果这个端口已被占用,wslhost 无法绑定 → 转发失败。但 WSL2 内部完全不受影响。
wsl hostname -I 获取 IP,浏览器访问 http://172.x.x.x:端口,前提是服务监听 0.0.0.0)。| 监听地址 | WSL2 内 curl | Windows localhost | WSL2 IP 直连 | 局域网 |
|---|---|---|---|---|
127.0.0.1 | ✅ | ⚠️ 仅依赖 wslhost | ❌ | ❌ |
0.0.0.0 | ✅ | ✅ 转发 + IP 直连 | ✅ | ✅ 需防火墙 |
路径A: wslhost 转发(依赖 WSL2 自动机制)
路径B: WSL2 IP 直连(不依赖 wslhost)
即使转发因休眠失效,路径B仍然可用。
在 WSL2 中监听 127.0.0.1 不意味着"对 Windows 不可见"——wslhost 仍然会把它转发到 Windows。这是 WSL2 的设计特性,不是安全边界。
| 类型 | 本质 | 表现 | 第一验证 |
|---|---|---|---|
| 进程没启动 | 没有人在等 | Connection refused | 终端有无报错 |
| 监听地址不对 | 没在门口等 | WSL 内通,Windows 不通 | 确认 --host 参数 |
| 端口被占用 | 门牌号已被用 | EADDRINUSE | ss -ltnp |
| 端口被系统保留 | 管理层禁止 | 无明显占用但不能绑 | netsh excludedportrange |
浏览器安全策略。网页向不同"源"(协议+主机+端口)发请求时,浏览器检查对方是否允许。源的三要素中任何一个不同,就是跨源。
端口都不通 → 先修端口,不是 CORS。
Status (failed) → 连接失败,不是 CORS。
HTTP 200 但被浏览器拦截 → 这才是 CORS。
开发中最简单的解决:前端 dev server 代理 API。
HTML 返回成功 → 查 CSS/JS。Network 面板 filter: stylesheet,看 Request URL 的端口是否正确。确认前端服务是否在运行。
服务正常,转发问题。wsl --shutdown → 重开 WSL → 重启服务。还不通就检查 Windows 端口保留。
原端口被占用,服务悄悄换到下一个。使用 --strictPort 让它在端口不对时报错而非悄悄成功。
最常见的"玄学"问题。根因:Hyper-V 网络未恢复。验证:wsl curl -I http://127.0.0.1:端口 成功 + Test-NetConnection 失败。解决:wsl --shutdown。
ss -ltnp
curl -I http://127.0.0.1:端口
lsof -i :端口
hostname -I
wsl --shutdownTest-NetConnection 127.0.0.1 -Port 端口
Get-NetTCPConnection -LocalPort 端口
netsh int ipv4 show excludedportrange protocol=tcp
wsl --shutdown
wsl hostname -I| 学习阶段 | 要掌握的问题 | 推荐搜索词 |
|---|---|---|
| 基础 | 进程、端口、监听是什么意思 | what does listen on a port mean |
| 地址 | 127.0.0.1 / localhost / 0.0.0.0 区别 | 127.0.0.1 vs 0.0.0.0 explained |
| 回环接口 | lo 接口本质, 不同环境的 127 | loopback interface network namespace |
| WSL2 网络 | Windows 和 WSL2 互访、转发机制 | WSL2 localhost forwarding |
| wslhost | wslhost.exe 如何实现端口转发 | wslhost.exe VMBus Hyper-V socket |
| 前端开发 | Vite HMR、WebSocket、资源 URL | Vite dev server HMR WebSocket |
| 浏览器安全 | CORS 按 origin 判断 | CORS origin protocol host port |
127.0.0.1 是回环地址,数据不经过物理网卡。每个网络命名空间有独立的 lo 接口——Windows、WSL2、Docker 的 127.0.0.1 彼此隔离。0.0.0.0 是监听地址(在所有网卡上监听),不是浏览器访问地址。wslhost.exe + VMBus 实现——它是 Windows 访问 WSL2 服务的"地下通道"。wsl --shutdown 是修复 WSL2 网络问题的最高频命令,不需要重启 Windows。0.0.0.0 比 127.0.0.1 多一条备用访问路径(IP 直连)。