Files
test-repo/docs/zh-cn/appendix/2-development-tools/ports-localhost.md
T
sanbuphy 6098908eee feat(docs): add interactive demos and complete content for development tools
- Add Vue components for interactive demos (SSH auth, regex, env vars, ports)
- Complete markdown content for SSH, regex, environment variables, and ports
- Remove placeholder "待实现" sections and replace with detailed guides
- Add visual explanations for key concepts like ports and localhost
- Include practical examples and troubleshooting tips
- Add component for showing evolution from transistors to CPU
- Improve documentation structure and navigation
- Add security best practices for API keys and environment variables
2026-02-21 10:04:47 +08:00

249 lines
9.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 端口与 localhost
> 💡 **学习指南**:当你执行 `npm run dev`,终端里出现 `http://localhost:5173` 时,你有没有想过:`localhost` 是什么?`5173` 又代表什么?为什么有时候会报 `EADDRINUSE` 错误?本章就来把这些日常开发中天天见、却很少深究的概念一次讲透。
在开始之前,建议你先补两块"基础砖":
- **网络基础**:如果你不太清楚 IP 地址和 HTTP 的概念,可以先看 [计算机基础 - 网络通信](../1-computer-fundamentals/network-fundamentals.md) 部分。
- **终端基础**:如果你还不熟悉终端命令行,可以先看 [命令行与 Shell 脚本](./command-line-shell.md)。
---
## 0. 引言:那个天天见的 `localhost:5173` 到底是什么?
<DevServerFlowDemo />
每个开发者的日常都离不开这一行输出:
```
➜ Local: http://localhost:5173/
```
但你有没有想过,这短短一行字里,藏着好几个关键概念:
- **http://** → 通信协议(用什么语言对话)
- **localhost** → 目标地址(找谁)
- **:5173** → 端口号(找到之后,敲哪扇门)
搞懂这三件事,你就能理解 90% 的开发环境网络问题。接下来我们逐个拆解。
---
## 1. 什么是端口?(IP 是大楼,端口是房间号)
### 1.1 一个直觉比喻
想象一台服务器是一栋大楼:
- **IP 地址**(如 `192.168.1.100`)就是大楼的门牌地址——告诉你"去哪栋楼"。
- **端口号**(如 `:80`)就是楼里的房间号——告诉你"进哪间房"。
一栋楼里可以同时有餐厅(80 号房)、咖啡厅(443 号房)、办公室(22 号房)。同理,一台电脑上可以同时运行 Web 服务器、数据库、SSH 服务,各自占用不同的端口。
👇 **动手点点看**
点击下面的"房间门牌",模拟向不同端口发起连接。注意观察:当端口"开着"(有程序在监听)和"关着"时,分别会发生什么?
<PortAnalogyDemo />
### 1.2 端口号的取值范围
端口号是一个 **065535** 之间的整数(共 65536 个)。这么多端口被分为三个区间:
| 区间 | 范围 | 用途 | 举例 |
| :--- | :--- | :--- | :--- |
| **系统端口** | 0 – 1023 | 预留给标准协议,普通用户不能随意占用 | 80 (HTTP)、443 (HTTPS)、22 (SSH) |
| **注册端口** | 1024 49151 | 给常见应用注册使用 | 3306 (MySQL)、5432 (PostgreSQL)、6379 (Redis) |
| **动态端口** | 49152 65535 | 操作系统临时分配 | 浏览器发请求时,系统随机分配一个源端口 |
> 为什么你的开发服务器喜欢用 3000、5173、8080?因为这些都在"注册端口"范围内,不需要管理员权限就能监听,又不太容易和系统服务冲突。
### 1.3 开发中常见的端口号速查
👇 **动手点点看**
输入端口号或服务名搜索,点击任意一行可以展开查看使用示例。
<CommonPortsDemo />
---
## 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 的几种写法和区别。
<LocalhostLoopbackDemo />
### 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 号房已经有人住了,你进不去!"**
常见的冲突场景:
- 上次的开发服务器没关干净,还在后台运行
- 两个不同的项目用了相同的默认端口
- 某个系统服务已经占用了你想要的端口
👇 **动手点点看**
试着在下面的模拟器里多次启动服务。当端口冲突时,对比"直接启动"和"智能启动"的不同处理方式。
<PortConflictDemo />
### 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: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**
```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. 实战排查:三个最常见的问题
👇 **动手点点看**
选择一个你遇到过的问题,跟着步骤一起排查。每一步都可以点击"执行"查看输出。
<PortTroubleshootDemo />
---
## 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 是开发环境中最基础、最高频的概念:
- **端口** = 一台机器上区分不同服务的"门牌号"065535
- **localhost** = "自己找自己"的特殊地址(127.0.0.1),数据不出本机
- **端口冲突**的本质是"一个门牌只能挂一块牌子"
- **跨域**的本质是"端口不同 = 不同源",需要 CORS 或代理来解决
记住这四句话,你在开发环境里遇到的大多数网络问题,都能快速定位原因。