Node.js 入门教程很多,但真正能帮你在 1 小时内把安装、验证、编码、跑通全部走完的并不多。这篇文章以“从下载 Node.js 到写出第一个 Web 应用”为主线,把 60 分钟拆成四段:前 10 分钟搞清楚 Node.js 是干什么的、版本怎么选;中间 15 分钟完成安装和 npm 基础配置;接下来 20 分钟用 Node.js 自带模块写一个能访问的 Web 页面;最后 15 分钟排查安装和运行时最常见的报错。这样做的好处是,每一步都能验证结果,不会出现“环境配了一下午,代码一跑全是问题”的情况。
1. 先搞清楚 Node.js 是干什么的,再决定安装哪个版本
1.1 Node.js 不是普通脚本工具,而是一个 JavaScript 运行时
Node.js 的官方定位是“基于 Chrome V8 引擎的 JavaScript 运行时”。通俗一点说,浏览器给 JavaScript 提供了window、document、fetch等环境,而 Node.js 给 JavaScript 提供了文件读取、网络请求、进程管理、操作系统交互等能力。
这意味着你不再需要通过 HTML 页面来运行 JavaScript,可以直接在终端执行:
node -e "console.log('hello node')"这行命令会创建一个 Node.js 进程,执行字符串里的 JavaScript 代码,然后把结果输出到控制台。对刚入门的人来说,只要理解这一点就够了:Node.js 让 JavaScript 从“只能操作页面”变成“可以操作文件和网络”的通用语言。
1.2 事件驱动、非阻塞 I/O 到底影响什么
很多资料会提到“事件驱动”“非阻塞 I/O”“单线程”。这里用一句更贴近实际的话解释:Node.js 遇到耗时操作时,不会一直卡住等待结果,而是先继续处理其他请求,等耗时操作完成后通过回调继续处理。
看一个简单对比:
// 模拟耗时读取,不推荐生产环境使用 fs.readFileSync const fs = require('fs'); console.log('1. 开始读取'); const data = fs.readFileSync('example.txt', 'utf8'); console.log('2. 读取完成:', data.length); console.log('3. 继续执行');上面这段用同步方式读文件,执行到第二行时,整个进程会等待文件读完,才继续执行第三行。如果改用异步方式:
const fs = require('fs'); console.log('1. 开始读取'); fs.readFile('example.txt', 'utf8', (err, data) => { console.log('2. 读取完成:', data ? data.length : 'error'); }); console.log('3. 继续执行');执行顺序会变成“1、3、2”。异步 I/O 是 Node.js 能同时处理大量并发请求的重要原因。对于刚入门的第一个 Web 应用,你不需要立刻精通它,但必须理解:fs.readFile的回调不会阻塞后续代码。
1.3 LTS、Current、偶数版本号怎么选
安装 Node.js 前,最容易出错的是版本选择。官方发布版本大致分两类:
| 版本类型 | 说明 | 适合场景 |
|---|---|---|
| LTS | Long Term Support,长期支持版本,会持续维护和修复漏洞 | 推荐新手、生产环境、企业项目 |
| Current | 当前版本,包含新特性,但迭代快、可能不稳定 | 尝鲜、特性验证、短期学习 |
| 偶数版本 | 例如 18、20、22,通常更容易进入 LTS 周期 | 稳定性优先的项目 |
| 奇数版本 | 例如 19、21、23,通常是过渡版本 | 不建议作为主力 |
实际项目里,建议安装当前最新 LTS,而不是最新 Current。原因很直接:很多 npm 包对 Node.js 版本有要求,LTS 版本生态兼容更好,遇到问题时搜索引擎能找到更多答案。
1.4 安装前的环境检查清单
安装前先检查操作系统、CPU 架构和是否已存在旧版本:
# Windows PowerShell systeminfo | findstr /C:"OS" # Linux / macOS uname -m # 检查是否已经安装过 Node.js node -v npm -vWindows 下尤其要注意架构:绝大多数现代电脑使用 64 位系统,应该下载x64安装包;部分旧电脑是 32 位系统,需要下载x86包。如果系统里已经安装了旧版 Node.js,先确认版本,避免安装新版本后 PATH 环境变量混乱。
2. 安装 Node.js 的三种方式,以及为什么推荐用 nvm
2.1 Windows 图形化安装包:最快但最不灵活
进入 Node.js 官网下载页,选择适合当前系统的.msi安装包,双击运行即可。安装过程中,默认已经包含“添加到 PATH”选项,一般不需要修改,一直下一步即可。
安装完成后,重新打开一个终端窗口,执行:
node -v npm -v如果输出类似:
v22.13.1 10.9.2说明安装成功。需要注意:安装完成后必须新开终端窗口,否则当前终端的 PATH 不会刷新,仍然提示找不到node命令。
这种方式适合只跑一次 Node.js、不打算切换项目的用户。缺点是,当某个项目依赖 Node.js 20,另一个项目依赖 Node.js 22 时,图形化安装包无法灵活切换版本。
2.2 Windows 下使用 nvm-windows 管理多版本
跨项目开发时,推荐使用 nvm(Node Version Manager)管理 Node.js 版本。Windows 上没有直接移植原版 nvm,常用的是 nvm-windows。安装方式:
- 从 nvm-windows 的发布页面下载安装包。
- 安装到一个不含中文和空格的目录,例如
C:\nvm。 - 安装完成后,终端执行:
nvm version然后安装并切换 Node.js 版本:
nvm install 22.13.1 nvm use 22.13.1 node -v执行nvm use后,node命令会指向 nvm 管理目录下的对应版本。这里的关键点是:不要直接到官网下载安装包和管理器混用,那会让node命令的来源不确定。
我的建议是:Windows 新项目统一用 nvm-windows,即使以后需要升级 Node.js 或同时维护旧项目,也不会被版本问题卡住。
2.3 macOS/Linux 下的 nvm 安装
macOS 或 Linux 用户可以使用官方脚本安装 nvm,但不要直接复制网上来路不明的curl脚本,应该先检查内容,再执行。
安装 nvm 后,shell 配置文件(通常是.zshrc或.bashrc)会追加 nvm 初始化脚本。安装完成要重新加载配置:
source ~/.zshrc然后安装 Node.js:
nvm install --lts nvm use --lts node -v--lts会安装当前最新的长期支持版本,避免手动指定容易过时的版本号。
2.4 安装完成后的检查点
无论使用哪种方式,都要完成以下检查:
| 检查项 | 命令 | 预期结果 |
|---|---|---|
| Node.js 可用 | node -v | 输出类似v22.13.1 |
| npm 可用 | npm -v | 输出类似10.9.2 |
| nvm 可用 | nvm version | 输出 nvm 版本号 |
| 全局路径 | npm root -g | 输出存在的全局 node_modules 目录 |
| 缓存路径 | npm config get cache | 输出 npm 缓存目录 |
如果node -v能正常输出,但npm -v报错,通常是因为安装包损坏、PATH 中存在多个 Node.js 目录或旧版残留。不要急着重装,先运行where node(Windows)或which node(Linux/macOS)确认实际执行路径。
3. 用 npm 做基础配置:镜像源、全局路径和缓存目录
3.1 npm 的职责与版本
npm 是 Node.js 自带的包管理器,负责下载、安装、卸载第三方依赖,并维护项目的依赖关系。它和node是两套程序:Node.js 负责运行 JavaScript,npm 负责管理 JavaScript 需要的库。
npm 的版本通常不等同于 Node.js 版本。安装 Node.js 后,npm 也一并安装。日常使用中,不要只关注node -v,还要关注npm -v。某些 CLI 工具会要求 npm 版本达到阈值,如果版本过旧,可以通过以下命令升级 npm:
npm install -g npm@latest3.2 配置镜像源,避免安装依赖超时
在实际网络环境里,直接从官方源安装依赖可能很慢,常见表现是npm install长时间停留在idealTree阶段,或者直接超时。可以把 npm 的 registry 切换到国内镜像:
npm config set registry https://registry.npmmirror.com/验证是否生效:
npm config get registry也可以直接查看配置文件位置:
npm config ls -l这里要注意的是:全局使用镜像源会影响所有项目。如果某些项目必须使用官方源或公司内网源,可以只在项目根目录创建.npmrc,写入:
registry=https://registry.npmjs.org/项目级配置会覆盖全局配置。这样就能做到“全局用镜像,个别项目用官方源”。
3.3 全局安装路径和权限
使用全局安装命令时:
npm install -g npm-check-updates全局包会安装到npm root -g指向的目录。Windows 下全局命令通常会被软链到 npm 前缀目录,如果没有正确配置,会出现“命令安装成功但终端找不到”的问题。
Linux/macOS 下,如果直接使用npm install -g遇到权限错误,不要用sudo强行安装,更推荐修改 npm 的全局目录到用户目录下:
mkdir -p ~/.npm-global npm config set prefix '~/.npm-global'然后在 shell 配置文件中添加:
export PATH=~/.npm-global/bin:$PATH这样全局安装的 CLI 工具都可以直接用,也避免了权限污染。
3.4 验证 npm 配置
配置完成后,创建一个临时目录测试 npm 是否能正常安装依赖:
mkdir npm-config-test cd npm-config-test npm init -y npm install lodash看到node_modules目录生成,并出现package-lock.json,说明安装链路正常。检查点有:
npm config get registry输出镜像地址。npm root -g输出一个可写目录。npm install没有权限和超时报错。
注意:不要在生产环境随意使用
npm cache clean --force。多数安装问题不是缓存损坏,而是镜像源或版本不对。强行清理缓存反而会拖慢下一次安装。
4. 创建第一个 Web 应用:使用内置 http 模块
4.1 初始化项目和目录结构
先创建项目目录:
mkdir node-first-app cd node-first-app npm init -ynpm init -y会生成一个默认的package.json,内容类似于:
{ "name": "node-first-app", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" } }对于第一个 Web 应用,这个文件不是必须修改的,但要理解它记录了三类信息:项目名称与版本、入口文件、启动脚本。后续添加第三方依赖时,dependencies也会写到这里。
4.2 最小可运行的 HTTP 服务器
新建server.js文件,写入:
const http = require('http'); const hostname = '127.0.0.1'; const port = 3000; const server = http.createServer((req, res) => { res.statusCode = 200; res.setHeader('Content-Type', 'text/plain; charset=utf-8'); res.end('Hello Node.js Web App'); }); server.listen(port, hostname, () => { console.log(`Server running at http://${hostname}:${port}/`); });这段代码的每一行都有明确作用:
require('http')导入 Node.js 内置的 HTTP 模块。http.createServer接收一个回调函数,每次有请求进来都会执行。req是请求对象,包含 URL、请求方法、请求头。res是响应对象,用来设置状态码、响应头和响应体。listening是网络层面的监听端口,这里指定127.0.0.1:3000。
4.3 解析请求参数和返回 JSON
第一个 Web 应用如果只有“Hello World”,还看不出实用价值。扩展一下:根据 URL 返回用户信息。
const http = require('http'); const url = require('url'); const server = http.createServer((req, res) => { const parsedUrl = new URL(req.url, `http://${req.headers.host}`); const pathname = parsedUrl.pathname; res.setHeader('Content-Type', 'application/json; charset=utf-8'); if (req.method === 'GET' && pathname === '/user') { const name = parsedUrl.searchParams.get('name') || 'anonymous'; res.statusCode = 200; res.end( JSON.stringify({ code: 0, data: { name, time: new Date().toISOString() } }) ); return; } res.statusCode = 404; res.end(JSON.stringify({ code: 404, message: 'Not Found' })); }); server.listen(3000, '127.0.0.1', () => { console.log('Server running at http://127.0.0.1:3000/'); });访问:
http://127.0.0.1:3000/user?name=node返回:
{"code":0,"data":{"name":"node","time":"2025-01-01T12:00:00.000Z"}}这里用到了URL对象,是 Node.js 内置的 URL 解析方式。比手动拆分字符串更可靠,也能处理中文参数、编码问题。
4.4 启动服务和验证接口
执行:
node server.js输出:
Server running at http://127.0.0.1:3000/然后打开浏览器访问http://127.0.0.1:3000/user?name=node,或者用命令行验证:
curl http://127.0.0.1:3000/user?name=node注意:
curl在 Windows PowerShell 中默认可能是Invoke-WebRequest的别名。如果输出格式不同,可以改用curl.exe,或者使用curl.exe -v查看详细请求过程。
验证成功后,按Ctrl + C终止服务器。这里最容易犯的错误是:修改server.js后没有重启进程。Node.js 不会自动加载代码修改,必须结束旧进程再启动。
5. 让开发更顺手:脚本、自动重启和调试
5.1 package.json 的 scripts
把启动命令写进package.json,项目就会更规范:
{ "name": "node-first-app", "version": "1.0.0", "main": "server.js", "scripts": { "start": "node server.js", "dev": "nodemon server.js" } }保存后,执行:
npm startnpm run dev需要先安装 nodemon,下面继续讲。
5.2 使用 nodemon 自动重启
开发时反复手动停止、启动服务器很低效。可以用 nodemon 监听文件变化,文件被保存时自动重启进程:
npm install -D nodemon安装后启动:
npx nodemon server.js这个依赖是开发依赖,只有开发环境需要。打包或部署生产环境时,不应该依赖 nodemon,而应该使用进程守护工具或容器管理。
5.3 命令行调试与内置调试器
最简单的故障定位方法是加日志:
const server = http.createServer((req, res) => { console.log(`${req.method} ${req.url}`); // ... });每来一个请求,终端都会输出请求方法和 URL。遇到浏览器请求/favicon.ico、请求路径不对、参数丢失时,日志是最快的证据。
如果日志不够,可以使用 Node.js 内置调试器:
node --inspect server.js然后打开 Chrome 的chrome://inspect,对 Node.js 进程进行断点调试。不过这个操作对刚入门的人可能略重,先从日志排查更实际。
5.4 通过日志和 curl 定位问题
下面是一个简单排查顺序:
- 先看终端有没有报错。
- 没有报错,再用
curl验证接口,而不是只看浏览器。 - 比较浏览器和
curl的响应差异,定位请求方法、请求头、请求参数问题。 - 如果接口返回 404,先打印
req.url。 - 如果接口返回乱码,检查
Content-Type是否带charset=utf-8。 - 如果请求一直超时,检查端口是否被占用、
server.listen是否配置正确、防火墙是否拦截。
6. 常见安装和运行问题排查
6.1 Windows 安装报错或缺少 Visual C++ Runtime
在 Windows 安装某些 Node.js 安装包时,可能输出“需要 Microsoft Visual C++ 2015-2022 Redistributable”相关提示。这不是 Node.js 本身损坏,而是操作系统缺少运行库。
处理方式:
- 安装微软官方提供的 Visual C++ Redistributable 包。
- 安装完成后重启电脑,再重新安装 Node.js。
- 不要在同一个系统里反复安装多个
.msi和.zip版 Node.js,容易导致 PATH 混乱。
6.2 输入 node -v 提示不是内部或外部命令
常见原因有三个:
- 安装完成后没有新开终端窗口。
- 安装时没有勾选“添加到 PATH”。
- 系统存在旧版本残留,多条 PATH 互相干扰。
排查方式:
where node echo %PATH%如果where node找到多个路径,通常说明旧版本或不同架构的 Node.js 混在一起。建议先卸载所有不用的 Node.js,只保留 nvm 管理的一个版本,再重新配置 PATH。
6.3 nvm install 提示 not yet released 或 not available
使用 nvm 安装具体版本时,可能看到:
error installing 22.13.1: Node.js v22.13.1 is not yet released or is not available这通常有两个原因:
- nvm 本地的版本列表太旧,还没有同步到最新版本。
- 你指定的版本号不正确,或者该版本不在当前 nvm 兼容列表中。
处理方式:
nvm list available先查可用版本,再选择列表中存在的版本号安装。如果列表里仍然没有,尝试升级 nvm-windows 到最新版本。不要凭感觉手写版本号,版本号必须和官方发布列表一致。
6.4 npm install 很慢或超时
优先检查 registry:
npm config get registry如果地址是官方源导致速度慢,按前面 3.2 节配置镜像源。如果已经是镜像源仍然慢,检查是否项目依赖了非常多的大型包,以及网络是否不稳定。不要频繁删除node_modules,那不是解决慢的首选方法。
6.5 端口被占用
启动服务器时出现:
Error: listen EADDRINUSE: address already in use :::3000说明 3000 端口已经被占用。查看占用进程:
# Windows netstat -ano | findstr :3000 # Linux / macOS lsof -i :3000找到 PID 后,确认进程可以结束再清理:
# Windows taskkill /PID 1234 /F也可以直接把server.js里的端口改成其他值,比如3001。实际开发中,端口应该通过环境变量配置,不写死在代码里。
6.6 修改代码后页面没变化
Node.js 不会热更新。如果修改了server.js但浏览器页面还是旧内容,优先确认终端里是否重启了服务器。如果使用 nodemon 却仍然没变化,检查正在执行的是不是nodemon server.js,以及文件保存位置是否在 nodemon 监听范围内。
注意:浏览器自带缓存也会造成“代码改了但页面没变”的假象。先用
curl请求接口,如果curl返回新内容,问题在浏览器缓存;如果curl也返回旧内容,问题在服务进程没有重启。
7. 把第一个 Web 应用扩展到接近生产形态
7.1 使用 Express 重写接口
内置http模块适合理解原理,但真实项目很少直接用它写业务接口。更多项目会使用 Express。先安装:
npm install express然后创建app.js:
const express = require('express'); const app = express(); const port = process.env.PORT || 3000; app.get('/', (req, res) => { res.send('Hello Node.js Web App'); }); app.get('/user', (req, res) => { const name = req.query.name || 'anonymous'; res.json({ code: 0, data: { name, time: new Date().toISOString() } }); }); app.listen(port, () => { console.log(`Server running at http://127.0.0.1:${port}/`); });Express 把路由、参数解析、JSON 响应都封装得更容易使用。学习和实际项目之间,顺序是:先会用http模块,再切换到 Express,最后再理解 Express 的中间件机制。
7.2 环境变量与默认值
第一个应用里端口写死为3000,这没问题,但生产环境通常不会固定端口。推荐方式:
const port = process.env.PORT || 3000;这样本地不配置时用 3000,部署平台注入PORT时读取平台端口。
学习环境可以直接在命令行运行。生产环境还要考虑:
- 日志写到文件或集中日志平台。
- 进程崩溃后自动重启。
- 配置信息通过环境变量传入。
- 监听地址根据部署平台调整。
- 增加健康检查接口。
7.3 目录规约和 .gitignore
即使只有几个文件,也可以从一开始建立规范:
node-first-app/ ├── app.js ├── package.json ├── package-lock.json └── .gitignore.gitignore至少要忽略:
node_modules/ .env *.lognode_modules是依赖安装后的目录,不应该提交到 Git,其他人拉取代码后通过npm install恢复。
7.4 学习环境与生产环境的差异
| 维度 | 学习环境 | 生产环境 |
|---|---|---|
| 启动方式 | node server.js或 nodemon | 进程守护工具、容器、CI/CD 平台 |
| 端口 | 写死或process.env.PORT || 3000 | 由平台注入环境变量 |
| 日志 | 终端输出 | 独立日志文件、日志收集系统 |
| 异常处理 | res.end直接返回 | 统一错误中间件、告警 |
| 依赖 | 开发依赖不区分 | npm ci --production生成可复现依赖 |
| 安全 | 仅本机访问 | 鉴权、限流、HTTPS、防火墙策略 |
这里最核心的理解是:能跑通不代表能上线。生产环境多出来的不是“更多代码”,而是对异常、可观测性、回滚和安全的约束。
7.5 可复用的检查清单
分享一份适合自己的项目发布前检查清单:
node -v与项目要求的 Node.js 版本一致。package.json的scripts.start能正常启动。- 接口使用
curl -i验证过状态码、响应头和响应体。 node_modules已加入.gitignore。- 端口没有写死,支持
process.env.PORT。 - 异常分支有日志,不会静默失败。
- 不使用裸
catch吞掉错误。 - 不需要在终端手工维持进程时,提供进程守护方案。
对于刚完成第一个 Web 应用的开发者,下一步可以按这个顺序扩展:先给接口增加表单提交和 JSON 请求体解析;然后加上简单的文件读写;接着学习 Express 中间件;再接触数据库连接和 ORM。每一步都保持“先起一个能跑的最小例子,再逐步加功能”,比一次性啃完 Node.js 所有 API 有效得多。