💡 学习指南:当你执行 npm run dev,终端里出现 http://localhost:5173 时,你有没有想过:localhost 是什么?5173 又代表什么?为什么有时候会报 EADDRINUSE 错误?本章就来把这些日常开发中天天见、却很少深究的概念一次讲透。

在开始之前,建议你先补两块"基础砖":


0. 引言:那个天天见的 localhost:5173 到底是什么?

每个开发者的日常都离不开这一行输出:

  ➜  Local:   http://localhost:5173/
  

但你有没有想过,这短短一行字里,藏着好几个关键概念:

  • http:// → 通信协议(用什么语言对话)
  • localhost → 目标地址(找谁)
  • :5173 → 端口号(找到之后,敲哪扇门)

搞懂这三件事,你就能理解 90% 的开发环境网络问题。接下来我们逐个拆解。


1. 什么是端口?(IP 是大楼,端口是房间号)

1.1 一个直觉比喻

想象一台服务器是一栋大楼:

  • IP 地址(如 192.168.1.100)就是大楼的门牌地址——告诉你"去哪栋楼"。
  • 端口号(如 :80)就是楼里的房间号——告诉你"进哪间房"。

一栋楼里可以同时有餐厅(80 号房)、咖啡厅(443 号房)、办公室(22 号房)。同理,一台电脑上可以同时运行 Web 服务器、数据库、SSH 服务,各自占用不同的端口。

👇 动手点点看: 点击下面的"房间门牌",模拟向不同端口发起连接。注意观察:当端口"开着"(有程序在监听)和"关着"时,分别会发生什么?

1.2 端口号的取值范围

端口号是一个 0–65535 之间的整数(共 65536 个)。这么多端口被分为三个区间:

区间 范围 用途 举例
系统端口 0 – 1023 预留给标准协议,普通用户不能随意占用 80 (HTTP)、443 (HTTPS)、22 (SSH)
注册端口 1024 – 49151 给常见应用注册使用 3306 (MySQL)、5432 (PostgreSQL)、6379 (Redis)
动态端口 49152 – 65535 操作系统临时分配 浏览器发请求时,系统随机分配一个源端口

为什么你的开发服务器喜欢用 3000、5173、8080?因为这些都在"注册端口"范围内,不需要管理员权限就能监听,又不太容易和系统服务冲突。

1.3 开发中常见的端口号速查

👇 动手点点看: 输入端口号或服务名搜索,点击任意一行可以展开查看使用示例。


2. 什么是 localhost?(自己找自己)

2.1 “环回"的核心概念

localhost 是一个特殊的域名,它永远指向你自己这台电脑

当你在浏览器输入 http://localhost:3000 时,发生了这些事:

  1. 浏览器问操作系统:"localhost 的 IP 是多少?”
  2. 操作系统直接回答:"127.0.0.1"(不需要联网查 DNS)
  3. 数据包发往 127.0.0.1,但不会真的离开本机
  4. 操作系统通过"环回接口(loopback interface)“把数据包折返回来
  5. 监听在 3000 端口上的程序收到请求,返回响应

整个过程不经过网线、不经过路由器、不需要联网。

👇 动手点点看: 点击"发送请求”,观察数据包的完整旅程。然后点击下方的"马甲卡片",了解 localhost 的几种写法和区别。

2.2 localhost vs 127.0.0.1 vs 0.0.0.0

这三个概念经常被混淆,但它们的含义完全不同:

写法 含义 谁能访问
localhost / 127.0.0.1 环回地址,仅本机 只有你自己的电脑
0.0.0.0 监听所有网络接口 本机 + 局域网内其他设备
192.168.x.x 局域网 IP 局域网内的设备

实际场景

  # 只有自己能访问(安全,适合开发)
npm run dev -- --host localhost

# 手机也能访问(适合移动端调试)
npm run dev -- --host 0.0.0.0
  

很多框架(如 Vite、Next.js)默认监听 localhost,所以你的手机即使连着同一个 WiFi 也访问不了。想用手机调试?加上 --host 参数就行。


3. 端口冲突:最常见的开发环境问题

3.1 为什么会冲突?

一个端口同一时刻只能被一个程序监听。 这就像一个房间只能住一户人家。

如果你尝试启动第二个服务在同一个端口上,就会看到这个经典错误:

  Error: listen EADDRINUSE :::3000
  

翻译成人话就是:“3000 号房已经有人住了,你进不去!”

常见的冲突场景:

  • 上次的开发服务器没关干净,还在后台运行
  • 两个不同的项目用了相同的默认端口
  • 某个系统服务已经占用了你想要的端口

👇 动手点点看: 试着在下面的模拟器里多次启动服务。当端口冲突时,对比"直接启动"和"智能启动"的不同处理方式。

3.2 排查与解决

遇到端口冲突时,排查流程非常固定:

macOS / Linux:

  # 第一步:查看谁在占用 3000 端口
lsof -i :3000

# 第二步:拿到 PID 后,强制终止
kill -9 <!-- TODO: PID START -->
  

Windows:

  # 第一步:查看谁在占用 3000 端口
netstat -ano | findstr :3000

# 第二步:终止进程
taskkill /PID <!-- TODO: PID START --> /F
  

很多现代框架(Vite、Create React App 等)遇到端口冲突时会自动询问"是否换一个端口?"。但了解底层原理,能帮你更快地排查那些框架帮不了你的疑难杂症。


4. 开发中的"同源策略"与跨域

4.1 什么是"源"?

浏览器有一个安全机制叫做同源策略(Same-Origin Policy):只有协议、域名、端口三者完全一致,才算"同源"。

地址 A 地址 B 是否同源 原因
http://localhost:5173 http://localhost:5173/about ✅ 同源 协议、域名、端口都一样
http://localhost:5173 http://localhost:3000 ❌ 不同源 端口不同(5173 vs 3000)
http://localhost:5173 https://localhost:5173 ❌ 不同源 协议不同(http vs https)

4.2 为什么前后端分离必然遇到跨域?

当你的项目架构是:

  前端 (Vite)  →  http://localhost:5173
后端 (Express) →  http://localhost:3000
  

前端页面从 :5173 加载,然后用 fetch('/api/users') 去请求 :3000 的接口——端口不一样,触发跨域限制!

两种常见解决方案:

方案一:后端配置 CORS

  // Express 后端
app.use(cors({ origin: 'http://localhost:5173' }))
  

方案二:前端配置代理(推荐)

  // vite.config.js
export default {
  server: {
    proxy: {
      '/api': 'http://localhost:3000'
    }
  }
}
  

代理的原理:让 Vite 开发服务器帮你"转发"请求。浏览器以为自己在和 :5173 通信(同源),实际上 Vite 在背后偷偷帮你把请求转给了 :3000


5. 实战排查:三个最常见的问题

👇 动手点点看: 选择一个你遇到过的问题,跟着步骤一起排查。每一步都可以点击"执行"查看输出。


6. 名词对照表

英文术语 中文对照 解释
Port 端口 一个 0–65535 的数字,用来区分同一台机器上的不同网络服务。每个服务"监听"一个端口,等待客户端连接。
localhost 本地主机 一个特殊域名,永远指向本机(127.0.0.1)。用于在不联网的情况下访问本机上运行的服务。
Loopback Interface 环回接口 操作系统的虚拟网络接口。发往 127.0.0.1 的数据包不会离开本机,而是通过该接口"折返"回来。
EADDRINUSE 地址已被使用 Node.js / 操作系统报的错误,表示你要监听的端口已经被另一个程序占用了。
CORS 跨域资源共享 浏览器安全机制。当前端页面尝试请求不同源(协议/域名/端口不同)的接口时,需要后端明确许可。
Same-Origin Policy 同源策略 浏览器的安全基石:只允许同协议、同域名、同端口的请求自由通信,阻止跨域的数据读取。
Proxy 代理 在开发环境中,代理服务器代替浏览器向后端转发请求,绕过浏览器的同源限制。
0.0.0.0 所有接口 当服务监听 0.0.0.0 时,表示它接受来自任何网络接口(本机、局域网等)的连接。
Well-known Ports 知名端口 0–1023 端口的统称,预留给 HTTP (80)、HTTPS (443)、SSH (22) 等标准协议。
PID 进程 ID 操作系统为每个运行中的程序分配的唯一编号,用于管理和终止进程。
lsof 列出打开的文件 macOS/Linux 命令,用于查看哪个进程占用了某个端口(lsof -i :端口号)。
HMR 热模块替换 开发服务器的功能:你修改代码后,浏览器自动更新,无需手动刷新页面。底层通过 WebSocket 通知浏览器。

总结

端口和 localhost 是开发环境中最基础、最高频的概念:

  • 端口 = 一台机器上区分不同服务的"门牌号"(0–65535)
  • localhost = “自己找自己"的特殊地址(127.0.0.1),数据不出本机
  • 端口冲突的本质是"一个门牌只能挂一块牌子”
  • 跨域的本质是"端口不同 = 不同源",需要 CORS 或代理来解决

记住这四句话,你在开发环境里遇到的大多数网络问题,都能快速定位原因。

Last updated 26 Apr 2026, 03:21 +0800 . history