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.1、localhost、0.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 常见应用使用,开发中最常见 3000、5173、8080、3306
动态端口 49152-65535 操作系统临时分配 浏览器请求外部网站时使用的源端口

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

常见端口速查

端口 服务 用途 暴露风险
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 解决。