Skip to content

端口与 localhost

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

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


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

1
2
3
4
5
1. 你执行 npm run dev
终端
$ npm run dev

> vite

  准备就绪...
监听
浏览器
等待你打开浏览器...
💡 你在终端里敲下启动命令
什么是 HTTP 服务器?
🏪
想象一个前台窗口HTTP 服务器就像一个"永远开着的服务窗口"——它一直等在那里,有人来问就回答,没人来就静静等着。
📋
只懂一种"暗号"这个窗口只听得懂 HTTP 协议的请求格式(比如 GET /index.html),然后把对应的文件内容返回给你。
⚙️
开发服务器 = 加强版窗口Vite、Webpack 的开发服务器不只是"原样返回文件",它还会即时编译你的代码(Vue → JS、TS → JS、Sass → CSS),然后再返回给浏览器。
一句话总结:开发服务器 = 一个运行在 localhost 上的 HTTP 服务器 + 即时代码编译器。它监听某个端口,浏览器来请求,它就把编译好的代码返回。

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

➜  Local:   http://localhost:5173/

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

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

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


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

1.1 一个直觉比喻

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

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

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

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

选择一栋"大楼":
Web 服务器大楼IP: 192.168.1.100
80
HTTP网页访问入口
🟢 监听中
443
HTTPS加密网页入口
🟢 监听中
22
SSH远程管理通道
🟢 监听中
3306
MySQL数据库(已关闭)
🔴 已关闭
核心比喻:IP 地址 = 大楼地址,端口号 = 房间门牌号。一台电脑上可以同时运行多个服务,每个服务"占用"一个端口号,就像同一栋大楼里的不同房间。

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邮件发送注意
0 – 1023
系统端口预留给标准服务(HTTP、SSH 等),普通用户不能随便占用。
1024 – 49151
注册端口留给常见应用(MySQL 3306、Redis 6379 等),开发中最常遇到的范围。
49152 – 65535
动态端口操作系统临时分配的端口,比如你的浏览器发请求时,系统会随机给你一个。
安全提醒:数据库端口(3306、5432、27017、6379)绝对不要直接暴露到公网!生产环境应只允许内网访问或通过 SSH 隧道连接。

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 的几种写法和区别。

🔗
🌐
浏览器你在地址栏输入 URL
📖
DNS 解析localhost → 127.0.0.1(不出网)
🔄
网络层数据包发往 127.0.0.1(环回接口)
⚙️
本机服务端口 3000 上的程序接收请求
📨
返回响应{ "message": "Hello!" }
你的应用(浏览器)
请求不离开本机
本地服务(:3000)
localhost 的"马甲"们(点击查看说明)
localhost→ 127.0.0.1
127.0.0.1→ 127.0.0.1
::1→ ::1
0.0.0.0→ 0.0.0.0
标准域名别名: 这是写在你电脑 /etc/hosts 文件里的映射。浏览器看到 localhost 时,直接解析为 127.0.0.1,不会去问 DNS 服务器。
核心概念:localhost 就是"自己找自己"。数据包通过环回接口(loopback interface)在本机内部折返,不经过网线、不经过路由器,速度极快且完全安全。

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局域网内的设备

实际场景

bash
# 只有自己能访问(安全,适合开发)
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 号房已经有人住了,你进不去!"

常见的冲突场景:

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

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

尝试启动:React 项目(默认端口 5173)
当前运行的服务1 个
Vite 前端:5173🟢 运行中
端口冲突:一个端口同一时刻只能被一个程序监听。如果你看到 EADDRINUSE 错误,说明这个端口已经被占了。要么杀掉旧进程,要么换个端口。

3.2 排查与解决

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

macOS / Linux:

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

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

Windows:

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

# 第二步:终止进程
taskkill /PID <PID> /F

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


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

4.1 什么是"源"?

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

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

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

当你的项目架构是:

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

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

两种常见解决方案:

方案一:后端配置 CORS

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

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

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

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


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

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

选择一个常见问题:
🔴
端口被占用Error: listen EADDRINUSE :::3000
排查步骤 (1/3)
$lsof -i :3000
查看谁在用这个端口
排查口诀:先确认服务有没有启动(lsof / netstat),再确认端口对不对,最后确认是不是跨域问题。90% 的 localhost 问题都逃不出这三步。

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 或代理来解决

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