适用读者:Node.js 初学者、前端开发者、后端入门者
目标:手把手教你创建并运行第一个 Node.js 应用,理解基本工作流程
1. 引言:你的第一个 Node.js 应用
创建第一个应用是学习任何编程语言或框架的里程碑。在 Node.js 中,这一步尤为简单且意义非凡——你即将体验 JavaScript 在服务器端的强大能力。
本章将带你:
- 创建控制台应用
- 构建简单的 HTTP 服务器
- 理解 Node.js 应用结构
- 学习基本的调试和运行方法
2. 环境准备:确保一切就绪
在开始之前,请确认 Node.js 已正确安装:
# 检查 Node.js 版本
node -v
# 预期输出: v18.13.0 或类似版本
# 检查 npm 版本
npm -v
# 预期输出: 8.19.3 或类似版本
2.1 创建项目目录
# 创建项目目录
mkdir first-node-app
cd first-node-app
# 初始化 npm 项目
npm init -y
# 查看生成的 package.json
cat package.json
2.2 目录结构
创建以下目录结构:
first-node-app/
├── node_modules/ # 自动创建,存放 npm 包
├── src/ # 源代码目录
│ ├── app.js # 主应用文件
│ └── server.js # 服务器文件
├── package.json # 项目配置文件
└── README.md # 项目说明文件(可选)
3. 创建控制台应用
3.1 基本控制台输出
创建 src/app.js 文件:
// src/app.js
// 控制台输出
console.log('Hello, Node.js!');
// 获取当前时间
const currentTime = new Date();
console.log('当前时间:', currentTime.toLocaleString());
// 计算简单表达式
const result = 2 + 3 * 5;
console.log('计算结果:', result);
// 访问进程信息
console.log('Node.js 版本:', process.version);
console.log('平台:', process.platform);
console.log('当前工作目录:', process.cwd());
3.2 处理命令行参数
修改 src/app.js 文件,添加命令行参数处理:
// src/app.js
// 获取命令行参数
const args = process.argv.slice(2);
const operation = args[0];
console.log('命令行参数:', args);
// 根据参数执行不同操作
switch (operation) {
case 'add':
const num1 = parseFloat(args[1]);
const num2 = parseFloat(args[2]);
if (isNaN(num1) || isNaN(num2)) {
console.log('错误: 请提供两个有效的数字');
} else {
console.log(`结果: ${num1 + num2}`);
}
break;
case 'greet':
const name = args[1] || 'World';
console.log(`Hello, ${name}!`);
break;
default:
console.log('可用操作:');
console.log(' - add <数字1> <数字2>: 两个数字相加');
console.log(' - greet <姓名>: 向指定的人问候');
}
3.3 运行控制台应用
# 基本运行
node src/app.js
# 输出:
# Hello, Node.js!
# 当前时间: 2023/1/15 14:30:45
# 计算结果: 17
# Node.js 版本: v18.13.0
# 平台: win32
# 当前工作目录: /path/to/first-node-app
# 使用 add 命令
node src/app.js add 5 7
# 输出: 结果: 12
# 使用 greet 命令
node src/app.js greet Alice
# 输出: Hello, Alice!
4. 创建 HTTP 服务器
4.1 基本服务器实现
创建 src/server.js 文件:
// src/server.js
// 导入 HTTP 模块
const http = require('http');
// 定义服务器配置
const hostname = '127.0.0.1';
const port = 3000;
// 创建 HTTP 服务器
const server = http.createServer((req, res) => {
// 设置响应头
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
// 发送响应内容
res.end('Hello, Node.js Server!\n');
});
// 启动服务器并监听端口
server.listen(port, hostname, () => {
// 服务器启动成功后的回调函数
console.log(`服务器运行在 http://${hostname}:${port}/`);
});
4.2 增强服务器功能
修改 src/server.js 文件,添加路由和响应处理:
// src/server.js
const http = require('http');
const fs = require('fs');
const path = require('path');
const hostname = '127.0.0.1';
const port = 3000;
const mimeTypes = {
'.html': 'text/html',
'.js': 'text/javascript',
'.css': 'text/css',
'.json': 'application/json',
'.png': 'image/png',
'.jpg': 'image/jpg',
'.gif': 'image/gif',
'.svg': 'image/svg+xml',
};
const server = http.createServer((req, res) => {
// 处理请求
console.log(`请求: ${req.method} ${req.url}`);
// 解析 URL
const url = new URL(req.url, `http://${req.headers.host}`);
const pathname = url.pathname;
// 处理不同路由
if (pathname === '/') {
// 首页路由
res.statusCode = 200;
res.setHeader('Content-Type', 'text/html');
res.end(`
<html>
<head>
<title>我的第一个 Node.js 应用</title>
</head>
<body>
<h1>Hello, Node.js!</h1>
<p>这是我的第一个 Node.js 服务器应用。</p>
<a href="/about">关于我们</a>
</body>
</html>
`);
} else if (pathname === '/about') {
// 关于页面路由
res.statusCode = 200;
res.setHeader('Content-Type', 'text/html');
res.end(`
<html>
<head>
<title>关于我们</title>
</head>
<body>
<h1>关于我们</h1>
<p>这是关于页面的内容。</p>
<a href="/">返回首页</a>
</body>
</html>
`);
} else if (pathname === '/api') {
// API 路由
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({
message: '欢迎使用我们的 API',
timestamp: new Date().toISOString()
}));
} else {
// 404 处理
res.statusCode = 404;
res.setHeader('Content-Type', 'text/html');
res.end(`
<html>
<head>
<title>页面未找到</title>
</head>
<body>
<h1>404 - 页面未找到</h1>
<p>抱歉,您访问的页面不存在。</p>
<a href="/">返回首页</a>
</body>
</html>
`);
}
});
server.listen(port, hostname, () => {
console.log(`服务器运行在 http://${hostname}:${port}/`);
console.log('按 Ctrl+C 停止服务器');
});
// 处理 uncaughtException 防止服务器崩溃
process.on('uncaughtException', (err) => {
console.error('未捕获的异常:', err);
});
4.3 运行 HTTP 服务器
# 启动服务器
node src/server.js
# 输出: 服务器运行在 http://127.0.0.1:3000/
# 测试访问
# 1. 在浏览器中访问 http://localhost:3000
# 2. 访问 http://localhost:3000/about
# 3. 访问 http://localhost:3000/api
# 4. 访问不存在的页面,如 http://localhost:3000/contact
# 使用 curl 测试
curl http://localhost:3000
curl http://localhost:3000/about
curl http://localhost:3000/api
5. 代码解析:理解 Node.js 应用工作原理
5.1 模块系统分析
// 导入内置模块
const http = require('http');
const fs = require('fs');
const path = require('path');
- http 模块:提供 HTTP 服务器和客户端功能
- fs 模块:提供文件系统操作 API
- path 模块:提供处理文件路径的工具
5.2 HTTP 服务器创建流程
5.3 请求处理流程
// 创建 HTTP 服务器
const server = http.createServer((req, res) => {
// req: request 对象,包含请求信息
// res: response 对象,用于构建响应
// 解析请求方法和 URL
console.log(`${req.method} ${req.url}`);
// 设置响应状态码
res.statusCode = 200;
// 设置响应头
res.setHeader('Content-Type', 'text/html');
// 发送响应体
res.end('<h1>Hello World</h1>');
});
5.4 服务器监听机制
// 启动服务器监听
server.listen(port, hostname, () => {
console.log(`服务器运行在 http://${hostname}:${port}/`);
});
- port:服务器监听端口号
- hostname:服务器监听的主机名/IP 地址
- 回调函数:服务器成功启动后执行
6. 进阶应用: 交互式用户信息
6.1 创建用户信息应用
创建 src/user.js 文件:
// src/user.js
const readline = require('readline');
// 创建 readline 接口
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
// 用户数据对象
const user = {
name: '',
age: 0,
email: '',
hobbies: []
};
// 询问用户姓名
rl.question('请输入您的姓名: ', (name) => {
user.name = name;
// 询问用户年龄
rl.question('请输入您的年龄: ', (age) => {
user.age = parseInt(age);
// 询问用户邮箱
rl.question('请输入您的邮箱: ', (email) => {
user.email = email;
// 询问用户爱好
rl.question('列出您的爱好 (用逗号分隔): ', (hobbiesStr) => {
user.hobbies = hobbiesStr.split(',').map(hobby => hobby.trim());
// 显示用户信息
console.log('\n用户信息:');
console.log(`姓名: ${user.name}`);
console.log(`年龄: ${user.age}`);
console.log(`邮箱: ${user.email}`);
console.log('爱好:');
user.hobbies.forEach(hobby => {
console.log(` - ${hobby}`);
});
// 关闭 readline 接口
rl.close();
});
});
});
});
// 监听 close 事件
rl.on('close', () => {
console.log('\n感谢使用本应用!');
process.exit(0);
});
6.2 运行用户信息应用
# 运行应用
node src/user.js
# 交互示例
# 请输入您的姓名: Alice
# 请输入您的年龄: 25
# 请输入您的邮箱: alice@example.***
# 列出您的爱好 (用逗号分隔): 阅读, 旅行, 摄影
#
# 用户信息:
# 姓名: Alice
# 年龄: 25
# 邮箱: alice@example.***
# 爱好:
# - 阅读
# - 旅行
# - 摄影
#
# 感谢使用本应用!
7. 调试技巧: 基本调试方法
7.1 使用 console.log 调试
// 在关键位置添加日志
const server = http.createServer((req, res) => {
console.log(`收到请求: ${req.method} ${req.url}`);
// 记录请求头
console.log('请求头:', req.headers);
// 处理请求...
console.log('发送响应');
res.end('Hello, Debug!');
});
7.2 使用 Node.js 调试器
// 在代码中添加断点
const fs = require('fs');
console.log('开始读取文件');
debugger; // 添加断点
fs.readFile('file.txt', 'utf8', (err, data) => {
if (err) throw err;
console.log('文件内容:', data);
});
console.log('结束');
运行调试:
# 使用 inspect 参数启动调试
node inspect src/server.js
# 使用 Chrome DevTools 调试
node --inspect-brk src/server.js
# 然后在 Chrome 浏览器中访问 chrome://inspect
# 点击 "Open dedicated DevTools for Node"
7.3 使用 VSCode 调试
- 在 VSCode 中打开项目
- 在需要调试的代码行左侧点击添加断点
- 按 F5 或点击 “Run and Debug” 图标
- 选择 “Node.js” 环境并运行
8. 总结与下一步
8.1 第一个应用回顾
- 控制台应用:学习基本输入输出和命令行参数处理
- HTTP 服务器:创建简单的 Web 服务器,处理路由和响应
- 交互式应用:使用 readline 模块创建命令行交互应用
- 调试基础:掌握 console.log 和 Node.js 调试器使用
8.2 关键概念理解
- 模块系统:如何导入和使用 Node.js 模块
- 事件驱动:理解服务器如何响应请求和处理事件
- 异步编程:了解回调函数的工作原理
- 请求/响应周期:HTTP 交互的基本流程
8.3 下一步学习路径
8.4 进阶项目建议
- 个人博客系统:使用 Express 框架和 MongoDB
- RESTful API 服务器:提供 CRUD 操作的数据接口
- 实时聊天应用:使用 Socket.IO 实现实时通信
- 命令行工具:创建 npm 包,发布到 npm 注册表
8.5 学习资源
- 官方文档:Node.js 官方文档
- 交互式教程:NodeSchool
- 实践项目:Node.js 蓝图项目
- 社区论坛:Node.js 官方论坛
最终建议:你的第一个 Node.js 应用只是开始。Node.js 的魅力在于其灵活性和强大的生态系统。通过不断实践和探索更多高级功能,你将能够构建从简单的 API 到复杂的实时应用的各种项目。保持好奇心,继续编程!