CC 咖啡猫的工作空间 Coding Space

端口与 localhost

原始素材:2-开发环境与工具/2.05-ports-localhost.md

这篇解决什么问题

当你执行 npm run dev,终端里出现:

Local: http://localhost:5173/

这短短一行里其实包含三个关键概念:

  • http://:通信协议,决定浏览器和服务端用什么规则对话。
  • localhost:目标地址,表示访问你自己的电脑。
  • :5173:端口号,表示访问这台电脑上的哪一个服务。

理解端口和 localhost,可以帮你解决很多开发环境里的常见问题:

  • 为什么 localhost:5173 能打开,手机却访问不了。
  • 为什么启动项目时报 EADDRINUSE
  • 为什么前端 5173 请求后端 3000 会跨域。
  • 为什么 127.0.0.1localhost0.0.0.0 不是一回事。
  • 为什么数据库端口不能直接暴露到公网。

开发服务器是什么

开发服务器可以理解为一个运行在本机上的 HTTP 服务。它一直监听某个端口,等待浏览器请求。

以 Vite 为例:

浏览器请求 http://localhost:5173/
  -> Vite 开发服务器收到请求
  -> 即时编译 Vue / React / TypeScript / CSS
  -> 返回浏览器可执行的 HTML、JS、CSS

所以开发服务器不是简单的「打开文件」,它通常还负责:

  • 本地 HTTP 服务。
  • 即时代码编译。
  • 模块解析。
  • HMR 热更新。
  • 静态资源返回。
  • API 代理。

什么是端口

可以把一台电脑想象成一栋大楼:

  • IP 地址是大楼地址,告诉你去哪台机器。
  • 端口号是房间号,告诉你找这台机器上的哪个服务。

一台电脑可以同时运行多个网络服务:

服务 常见端口 说明
HTTP 80 普通网页访问
HTTPS 443 加密网页访问
SSH 22 远程登录
MySQL 3306 MySQL 数据库
Redis 6379 Redis 缓存
Vite 5173 前端开发服务器

端口的本质是操作系统用来区分网络服务的编号。客户端连到某台机器后,操作系统根据端口号把连接交给对应的进程。

端口范围

端口号是 0-65535 之间的整数,共 65536 个。

区间 范围 用途 例子
系统端口 0-1023 预留给标准协议,通常需要管理员权限 80 HTTP、443 HTTPS、22 SSH
注册端口 1024-49151 常见应用使用,开发中最常见 3000517380803306
动态端口 49152-65535 操作系统临时分配 浏览器请求外部网站时使用的源端口

开发服务器常用 3000517380008080,因为它们不需要管理员权限,也不容易和系统标准服务冲突。

常见端口速查

端口 服务 用途 暴露风险
21 FTP 文件传输
22 SSH 远程登录 中,需要限制来源和密钥
25 SMTP 邮件发送
53 DNS 域名解析
80 HTTP 未加密网页访问 低到中
443 HTTPS 加密网页访问
3000 Node / React 本地开发服务 低,生产需谨慎
3306 MySQL 数据库 高,不应公网暴露
4200 Angular 本地开发服务
5000 Flask Python Web 服务 低到中
5173 Vite 本地开发服务
5432 PostgreSQL 数据库 高,不应公网暴露
6379 Redis 缓存 高,不应公网暴露
8000 Django / Python 本地或测试 HTTP 服务 低到中
8080 通用 HTTP 备用 HTTP、代理、Java 服务 低到中
27017 MongoDB 数据库 高,不应公网暴露

安全原则很简单:数据库、缓存、管理后台、SSH 等端口不要直接暴露到公网。生产环境应通过内网、安全组、防火墙、VPN、SSH 隧道或零信任访问控制来限制入口。

什么是 localhost

localhost 是一个特殊域名,表示「本机」。

当你访问:

http://localhost:3000

大致发生这些事:

  1. 浏览器把 localhost 交给操作系统解析。
  2. 操作系统把它解析为 127.0.0.1,通常不需要请求外部 DNS。
  3. 数据包发往 127.0.0.1
  4. 操作系统通过环回接口(loopback interface)把数据包折回本机。
  5. 监听在 3000 端口的程序收到请求并返回响应。

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

localhost、127.0.0.1、::1、0.0.0.0

这几个地址经常被混淆。

写法 含义 谁能访问 常见用途
localhost 本地主机域名,通常解析到 127.0.0.1::1 本机 本地开发
127.0.0.1 IPv4 环回地址 本机 明确访问 IPv4 本机服务
::1 IPv6 环回地址 本机 IPv6 环境下的本机访问
0.0.0.0 监听所有 IPv4 网络接口 本机和可达网络内设备 允许局域网访问开发服务
192.168.x.x 局域网地址 同一局域网设备 手机、平板访问电脑服务

关键区别:

  • 访问 localhost / 127.0.0.1:只找自己这台电脑。
  • 服务监听 localhost / 127.0.0.1:只有本机能访问。
  • 服务监听 0.0.0.0:本机所有网络接口都接收连接,局域网设备可能访问到。

例如:

# 只允许本机访问
npm run dev -- --host localhost

# 允许局域网设备访问,适合手机调试
npm run dev -- --host 0.0.0.0

很多框架默认只监听 localhost。所以手机和电脑连着同一个 Wi-Fi,也不一定能访问你的开发服务。要用手机调试,通常需要监听 0.0.0.0,然后用电脑的局域网 IP 访问,例如:

http://192.168.1.23:5173

端口冲突

一个端口同一时刻只能被一个进程监听。如果你启动第二个服务监听同一个端口,就会看到类似错误:

Error: listen EADDRINUSE :::3000

EADDRINUSE 的意思是 address already in use,也就是这个地址和端口已经被占用。

常见原因:

  • 上次的开发服务器没有关干净。
  • 两个项目使用了同一个默认端口。
  • 后台进程仍在运行。
  • 系统服务或 Docker 容器占用了端口。

如何排查端口占用

macOS / Linux

查看谁占用 3000 端口:

lsof -i :3000

输出里通常能看到进程名和 PID。终止进程:

kill -9 <PID>

如果想看监听端口,也可以使用:

lsof -nP -iTCP -sTCP:LISTEN

Windows

查看谁占用 3000 端口:

netstat -ano | findstr :3000

根据 PID 终止进程:

taskkill /PID <PID> /F

端口冲突的处理策略

遇到端口冲突,一般有三种处理方式:

方式 适合场景 注意点
杀掉旧进程 确认旧服务无用 不要误杀数据库、代理、系统服务
换一个端口 多项目同时运行 前端代理、回调地址也要同步改
配置固定端口 团队协作或文档固定 避免每个人随机端口造成沟通混乱

很多现代框架在端口被占用时会询问是否换端口。但如果前端、后端、OAuth 回调、WebSocket 地址已经写死,自动换端口可能会引出新的问题。

同源策略和跨域

浏览器的同源策略(Same-Origin Policy)规定:只有协议、域名、端口都一致,才算同源。

地址 A 地址 B 是否同源 原因
http://localhost:5173 http://localhost:5173/about 协议、域名、端口都一样
http://localhost:5173 http://localhost:3000 端口不同
http://localhost:5173 https://localhost:5173 协议不同
http://localhost:5173 http://127.0.0.1:5173 域名不同,虽然都指向本机

这也是前后端分离项目常见跨域问题的来源:

前端开发服务器: http://localhost:5173
后端 API 服务:  http://localhost:3000

端口不同,浏览器就认为它们不同源。

跨域的两种常见解决方案

方案一:后端配置 CORS

后端明确允许前端源访问:

// Express 示例
app.use(cors({
  origin: 'http://localhost:5173',
}));

适合后端可控、需要真实跨源访问的情况。

方案二:前端开发服务器代理

在开发环境中,让前端开发服务器转发 API 请求:

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

浏览器请求的是:

http://localhost:5173/api/users

Vite 在服务端把请求转发给:

http://localhost:3000/api/users

浏览器只看到同源请求,所以不会触发跨域限制。

三类常见问题排查

1. 端口被占用

现象:

Error: listen EADDRINUSE :::3000

排查:

lsof -i :3000

处理:

  • 杀掉旧进程。
  • 换端口。
  • 检查 Docker、IDE、后台任务是否还在运行。

2. 连接被拒绝

现象:

ERR_CONNECTION_REFUSED

常见原因:

  • 服务没启动。
  • 端口写错。
  • 服务只监听 localhost,但你从局域网设备访问。
  • 防火墙或安全软件阻止连接。

排查顺序:

  1. 看终端服务是否启动成功。
  2. lsof -i :端口netstat 确认监听。
  3. 本机先访问 localhost:端口
  4. 局域网访问时确认服务监听 0.0.0.0
  5. 检查防火墙和安全组。

3. 跨域被拦截

现象:

Access to fetch at ... from origin ... has been blocked by CORS policy

排查:

  • 看浏览器控制台错误。
  • 看 Network 面板里的请求地址、状态码和响应头。
  • 确认协议、域名、端口是否一致。
  • 确认后端是否返回 Access-Control-Allow-Origin
  • 开发环境优先考虑配置代理。

排查口诀

遇到 localhost 问题,可以按这个顺序走:

服务是否启动
  -> 端口是否正确
  -> 监听地址是否正确
  -> 本机能否访问
  -> 局域网能否访问
  -> 是否跨域
  -> 是否被防火墙或代理拦截

不要一上来就猜跨域。很多问题其实是服务没启动、端口写错或监听地址不对。

名词对照表

英文术语 中文对照 解释
Port 端口 一个 0-65535 的数字,用来区分同一台机器上的不同网络服务。
localhost 本地主机 特殊域名,通常指向本机环回地址。
Loopback Interface 环回接口 操作系统的虚拟网络接口,发往 127.0.0.1 的数据包不会离开本机。
EADDRINUSE 地址已被使用 表示要监听的端口已经被另一个进程占用。
CORS 跨域资源共享 浏览器安全机制,跨源请求需要服务端明确允许。
Same-Origin Policy 同源策略 浏览器安全基石:协议、域名、端口都一致才算同源。
Proxy 代理 在开发环境中代替浏览器向后端转发请求,常用于绕过跨域限制。
0.0.0.0 所有接口 服务监听所有网络接口,可能允许局域网访问。
Well-known Ports 知名端口 0-1023 端口,预留给 HTTP、HTTPS、SSH 等标准协议。
PID 进程 ID 操作系统为每个运行中程序分配的唯一编号。
lsof 列出打开的文件 macOS/Linux 下查看端口占用常用命令。
HMR 热模块替换 开发服务器在代码变更后通知浏览器更新页面的机制。

小结

  • 端口是同一台机器上区分不同服务的编号。
  • localhost 是本机地址,通常解析到 127.0.0.1,请求不会离开本机。
  • 0.0.0.0 是监听所有网络接口,常用于局域网调试,但要注意安全。
  • EADDRINUSE 表示端口已经被占用。
  • 浏览器同源由协议、域名、端口共同决定,端口不同也会跨域。
  • 开发环境跨域通常用 CORS 或 dev server proxy 解决。