端口与 localhost
💡 学习指南:当你执行
npm run dev,终端里出现http://localhost:5173时,你有没有想过:localhost是什么?5173又代表什么?为什么有时候会报EADDRINUSE错误?本章就来把这些日常开发中天天见、却很少深究的概念一次讲透。
在开始之前,建议你先补两块"基础砖":
- 网络基础:如果你不太清楚 IP 地址和 HTTP 的概念,可以先看 计算机基础 - 网络通信 部分。
- 终端基础:如果你还不熟悉终端命令行,可以先看 命令行与 Shell 脚本。
0. 引言:那个天天见的 localhost:5173 到底是什么?
$ npm run dev
> vite
准备就绪...GET /index.html),然后把对应的文件内容返回给你。每个开发者的日常都离不开这一行输出:
➜ 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 开发中常见的端口号速查
👇 动手点点看: 输入端口号或服务名搜索,点击任意一行可以展开查看使用示例。
80HTTP网页访问(未加密)安全443HTTPS网页访问(加密)安全22SSH安全远程登录注意21FTP文件传输敏感3306MySQLMySQL 数据库敏感5432PostgreSQLPostgreSQL 数据库敏感27017MongoDBMongoDB 数据库敏感6379RedisRedis 缓存敏感3000Node/ReactNode.js / React 开发服务器安全5173ViteVite 开发服务器安全8080通用 HTTPHTTP 备用端口 / 代理安全8000Django/PythonDjango / Python HTTP 服务安全5000FlaskFlask 开发服务器安全4200AngularAngular 开发服务器安全53DNS域名解析注意25SMTP邮件发送注意2. 什么是 localhost?(自己找自己)
2.1 "环回"的核心概念
localhost 是一个特殊的域名,它永远指向你自己这台电脑。
当你在浏览器输入 http://localhost:3000 时,发生了这些事:
- 浏览器问操作系统:"
localhost的 IP 是多少?" - 操作系统直接回答:"
127.0.0.1"(不需要联网查 DNS) - 数据包发往
127.0.0.1,但不会真的离开本机 - 操作系统通过"环回接口(loopback interface)"把数据包折返回来
- 监听在 3000 端口上的程序收到请求,返回响应
整个过程不经过网线、不经过路由器、不需要联网。
👇 动手点点看: 点击"发送请求",观察数据包的完整旅程。然后点击下方的"马甲卡片",了解 localhost 的几种写法和区别。
localhost→ 127.0.0.1127.0.0.1→ 127.0.0.1::1→ ::10.0.0.0→ 0.0.0.0/etc/hosts 文件里的映射。浏览器看到 localhost 时,直接解析为 127.0.0.1,不会去问 DNS 服务器。 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 号房已经有人住了,你进不去!"
常见的冲突场景:
- 上次的开发服务器没关干净,还在后台运行
- 两个不同的项目用了相同的默认端口
- 某个系统服务已经占用了你想要的端口
👇 动手点点看: 试着在下面的模拟器里多次启动服务。当端口冲突时,对比"直接启动"和"智能启动"的不同处理方式。
:5173🟢 运行中EADDRINUSE 错误,说明这个端口已经被占了。要么杀掉旧进程,要么换个端口。 3.2 排查与解决
遇到端口冲突时,排查流程非常固定:
macOS / Linux:
# 第一步:查看谁在占用 3000 端口
lsof -i :3000
# 第二步:拿到 PID 后,强制终止
kill -9 <PID>Windows:
# 第一步:查看谁在占用 3000 端口
netstat -ano | findstr :3000
# 第二步:终止进程
taskkill /PID <PID> /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. 实战排查:三个最常见的问题
👇 动手点点看: 选择一个你遇到过的问题,跟着步骤一起排查。每一步都可以点击"执行"查看输出。
lsof -i :30006. 名词对照表
| 英文术语 | 中文对照 | 解释 |
|---|---|---|
| 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 或代理来解决
记住这四句话,你在开发环境里遇到的大多数网络问题,都能快速定位原因。
