Node.js完全指南:從入門到精通
一、Node.js基礎(chǔ)概念
1.1 什么是Node.js?
Node.js是一個(gè)基于Chrome V8引擎的JavaScript運(yùn)行環(huán)境,讓JavaScript可以在服務(wù)器端運(yùn)行。它使用事件驅(qū)動(dòng)、非阻塞I/O模型,使其輕量且高效。
1.2 Node.js的歷史
- 2009年:Ryan Dahl創(chuàng)建了Node.js
- 2010年:NPM(Node Package Manager)誕生
- 2011年:npm 1.0發(fā)布
- 2015年:Node.js基金會(huì)成立
- 2016年:引入長期支持(LTS)版本
- 至今:持續(xù)快速發(fā)展,廣泛應(yīng)用于后端開發(fā)
1.3 Node.js的特點(diǎn)
- 單線程:使用單線程事件循環(huán),避免線程切換開銷
- 異步非阻塞I/O:提高并發(fā)處理能力
- 跨平臺(tái):可在Windows、Linux、Mac上運(yùn)行
- NPM生態(tài):擁有世界上最龐大的開源庫生態(tài)系統(tǒng)
- JavaScript全棧:前后端統(tǒng)一語言,降低開發(fā)成本
1.4 Node.js的應(yīng)用場景
- Web應(yīng)用:RESTful API、GraphQL服務(wù)
- 實(shí)時(shí)應(yīng)用:聊天應(yīng)用、實(shí)時(shí)協(xié)作工具
- 微服務(wù):構(gòu)建分布式系統(tǒng)
- CLI工具:命令行工具開發(fā)
- 數(shù)據(jù)流:處理大量數(shù)據(jù)
- 物聯(lián)網(wǎng):IoT設(shè)備數(shù)據(jù)處理
二、Node.js安裝和環(huán)境配置
2.1 安裝Node.js
Windows系統(tǒng)
- 訪問Node.js官網(wǎng):https://nodejs.org/
- 下載LTS版本(推薦)或Current版本
- 運(yùn)行安裝程序,按提示完成安裝
- 驗(yàn)證安裝:
node --version npm --version
Linux系統(tǒng)
# 使用包管理器安裝 # Ubuntu/Debian sudo apt-get update sudo apt-get install nodejs npm # CentOS/RHEL sudo yum install nodejs npm # 使用NVM安裝(推薦) curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash source ~/.bashrc nvm install --lts nvm use --lts
Mac系統(tǒng)
# 使用Homebrew安裝 brew install node # 使用NVM安裝 curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash source ~/.bashrc nvm install --lts
2.2 版本管理
使用NVM(Node Version Manager)
# 安裝NVM curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash # 查看可用版本 nvm list-remote # 安裝特定版本 nvm install 16.14.0 # 使用特定版本 nvm use 16.14.0 # 設(shè)置默認(rèn)版本 nvm alias default 16.14.0 # 查看已安裝版本 nvm list # 卸載版本 nvm uninstall 16.14.0
使用n(簡單版本管理器)
# 安裝n npm install -g n # 安裝最新LTS版本 n lts # 安裝最新版本 n latest # 安裝特定版本 n 16.14.0 # 切換版本 n # 查看已安裝版本 n ls
2.3 環(huán)境變量配置
# Windows系統(tǒng) # 系統(tǒng)環(huán)境變量中添加: # NODE_PATH = C:\Users\YourName\AppData\Roaming\npm\node_modules # PATH = %NODE_PATH%;C:\Program Files\nodejs # Linux/Mac系統(tǒng) # 在 ~/.bashrc 或 ~/.zshrc 中添加: export NODE_PATH=/usr/local/lib/node_modules export PATH=$PATH:/usr/local/bin # 重新加載配置 source ~/.bashrc
2.4 創(chuàng)建第一個(gè)Node.js應(yīng)用
// hello.js
console.log('Hello, Node.js!');
// 運(yùn)行
node hello.js// http-server.js
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello, Node.js!');
});
server.listen(3000, () => {
console.log('Server running at http://localhost:3000/');
});
// 運(yùn)行
node http-server.js三、模塊系統(tǒng)
3.1 CommonJS模塊系統(tǒng)
導(dǎo)出模塊
// math.js
// 方式1:導(dǎo)出單個(gè)值
module.exports = {
add: function(a, b) {
return a + b;
},
subtract: function(a, b) {
return a - b;
}
};
// 方式2:導(dǎo)出多個(gè)值
exports.add = function(a, b) {
return a + b;
};
exports.subtract = function(a, b) {
return a - b;
};
// 方式3:導(dǎo)出類
class Calculator {
add(a, b) {
return a + b;
}
}
module.exports = Calculator;導(dǎo)入模塊
// app.js
// 方式1:導(dǎo)入整個(gè)模塊
const math = require('./math');
console.log(math.add(1, 2)); // 3
// 方式2:解構(gòu)導(dǎo)入
const { add, subtract } = require('./math');
console.log(add(1, 2)); // 3
// 方式3:導(dǎo)入類
const Calculator = require('./math');
const calc = new Calculator();
console.log(calc.add(1, 2)); // 33.2 ES6模塊系統(tǒng)
啟用ES6模塊
// package.json
{
"type": "module"
}
導(dǎo)出模塊
// math.mjs
// 方式1:命名導(dǎo)出
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
// 方式2:默認(rèn)導(dǎo)出
export default class Calculator {
add(a, b) {
return a + b;
}
}
// 方式3:混合導(dǎo)出
export const PI = 3.14159;
export function multiply(a, b) {
return a * b;
}導(dǎo)入模塊
// app.mjs
// 方式1:導(dǎo)入命名導(dǎo)出
import { add, subtract } from './math.mjs';
console.log(add(1, 2)); // 3
// 方式2:導(dǎo)入默認(rèn)導(dǎo)出
import Calculator from './math.mjs';
const calc = new Calculator();
console.log(calc.add(1, 2)); // 3
// 方式3:導(dǎo)入所有
import * as math from './math.mjs';
console.log(math.add(1, 2)); // 3
// 方式4:動(dòng)態(tài)導(dǎo)入
const module = await import('./math.mjs');
console.log(module.add(1, 2)); // 33.3 核心模塊
1. fs(文件系統(tǒng))
const fs = require('fs');
const path = require('path');
// 同步讀取文件
try {
const data = fs.readFileSync('input.txt', 'utf8');
console.log(data);
} catch (error) {
console.error('讀取文件失敗:', error);
}
// 異步讀取文件(推薦)
fs.readFile('input.txt', 'utf8', (error, data) => {
if (error) {
console.error('讀取文件失敗:', error);
return;
}
console.log(data);
});
// 使用Promise
const fsPromises = require('fs').promises;
async function readFileAsync() {
try {
const data = await fsPromises.readFile('input.txt', 'utf8');
console.log(data);
} catch (error) {
console.error('讀取文件失敗:', error);
}
}
// 寫入文件
fs.writeFile('output.txt', 'Hello, Node.js!', 'utf8', (error) => {
if (error) {
console.error('寫入文件失敗:', error);
return;
}
console.log('文件寫入成功');
});
// 追加內(nèi)容
fs.appendFile('output.txt', '\n追加的內(nèi)容', 'utf8', (error) => {
if (error) {
console.error('追加內(nèi)容失敗:', error);
return;
}
console.log('內(nèi)容追加成功');
});
// 刪除文件
fs.unlink('output.txt', (error) => {
if (error) {
console.error('刪除文件失敗:', error);
return;
}
console.log('文件刪除成功');
});
// 創(chuàng)建目錄
fs.mkdir('newdir', { recursive: true }, (error) => {
if (error) {
console.error('創(chuàng)建目錄失敗:', error);
return;
}
console.log('目錄創(chuàng)建成功');
});
// 讀取目錄
fs.readdir('.', (error, files) => {
if (error) {
console.error('讀取目錄失敗:', error);
return;
}
console.log('目錄內(nèi)容:', files);
});
// 檢查文件是否存在
fs.access('input.txt', fs.constants.F_OK, (error) => {
if (error) {
console.log('文件不存在');
} else {
console.log('文件存在');
}
});
// 獲取文件信息
fs.stat('input.txt', (error, stats) => {
if (error) {
console.error('獲取文件信息失敗:', error);
return;
}
console.log('文件信息:', stats);
console.log('是否為文件:', stats.isFile());
console.log('是否為目錄:', stats.isDirectory());
console.log('文件大小:', stats.size);
});
// 路徑操作
const filePath = path.join(__dirname, 'files', 'input.txt');
console.log('文件路徑:', filePath);
console.log('文件名:', path.basename(filePath));
console.log('目錄名:', path.dirname(filePath));
console.log('擴(kuò)展名:', path.extname(filePath));
console.log('絕對路徑:', path.resolve(filePath));2. http(HTTP服務(wù)器)
const http = require('http');
const url = require('url');
const querystring = require('querystring');
// 創(chuàng)建簡單的HTTP服務(wù)器
const server = http.createServer((req, res) => {
// 處理CORS
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
// 處理OPTIONS請求
if (req.method === 'OPTIONS') {
res.writeHead(200);
res.end();
return;
}
// 解析URL
const parsedUrl = url.parse(req.url, true);
const pathname = parsedUrl.pathname;
const query = parsedUrl.query;
console.log(`收到請求: ${req.method} ${pathname}`);
// 路由處理
if (pathname === '/') {
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.end(`
<!DOCTYPE html>
<html>
<head>
<title>Node.js HTTP服務(wù)器</title>
</head>
<body>
<h1>歡迎使用Node.js HTTP服務(wù)器</h1>
<p>當(dāng)前路徑: ${pathname}</p>
</body>
</html>
`);
} else if (pathname === '/api/data') {
// JSON響應(yīng)
const data = {
message: '成功',
data: [1, 2, 3, 4, 5]
};
res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
res.end(JSON.stringify(data));
} else {
// 404頁面
res.writeHead(404, { 'Content-Type': 'text/html; charset=utf-8' });
res.end(`
<!DOCTYPE html>
<html>
<head>
<title>404 Not Found</title>
</head>
<body>
<h1>404 - 頁面不存在</h1>
<p>您訪問的頁面不存在: ${pathname}</p>
</body>
</html>
`);
}
});
server.listen(3000, () => {
console.log('服務(wù)器運(yùn)行在 http://localhost:3000/');
});
// 處理POST請求
const server2 = http.createServer((req, res) => {
if (req.method === 'POST' && req.url === '/api/login') {
let body = '';
req.on('data', chunk => {
body += chunk.toString();
});
req.on('end', () => {
try {
const data = JSON.parse(body);
console.log('接收到的數(shù)據(jù):', data);
res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
res.end(JSON.stringify({
success: true,
message: '登錄成功',
user: data
}));
} catch (error) {
res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });
res.end(JSON.stringify({
success: false,
message: '數(shù)據(jù)格式錯(cuò)誤'
}));
}
});
} else {
res.writeHead(404, { 'Content-Type': 'text/html; charset=utf-8' });
res.end('404 Not Found');
}
});
server2.listen(3001, () => {
console.log('POST服務(wù)器運(yùn)行在 http://localhost:3001/');
});3. path(路徑處理)
const path = require('path');
// 路徑拼接
const fullPath = path.join(__dirname, 'files', 'data.txt');
console.log('完整路徑:', fullPath);
// 路徑解析
const parsed = path.parse('/path/to/file.txt');
console.log('路徑解析:', parsed);
// {
// root: '/',
// dir: '/path/to',
// base: 'file.txt',
// ext: '.txt',
// name: 'file'
// }
// 獲取文件名
console.log('文件名:', path.basename('/path/to/file.txt')); // file.txt
console.log('不含擴(kuò)展名的文件名:', path.basename('/path/to/file.txt', '.txt')); // file
// 獲取目錄名
console.log('目錄名:', path.dirname('/path/to/file.txt')); // /path/to
// 獲取擴(kuò)展名
console.log('擴(kuò)展名:', path.extname('/path/to/file.txt')); // .txt
// 獲取絕對路徑
console.log('絕對路徑:', path.resolve('files/data.txt'));
// 規(guī)范化路徑
console.log('規(guī)范化路徑:', path.normalize('/path/to/../to/./file.txt')); // /path/to/file.txt
// 判斷是否為絕對路徑
console.log('是否為絕對路徑:', path.isAbsolute('/path/to/file.txt')); // true
console.log('是否為絕對路徑:', path.isAbsolute('files/data.txt')); // false
// 獲取當(dāng)前工作目錄
console.log('當(dāng)前工作目錄:', process.cwd());
console.log('__dirname:', __dirname);
console.log('__filename:', __filename);4. events(事件處理)
const EventEmitter = require('events');
// 創(chuàng)建事件發(fā)射器
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
// 監(jiān)聽事件
myEmitter.on('event', () => {
console.log('事件觸發(fā)!');
});
// 觸發(fā)事件
myEmitter.emit('event');
// 帶參數(shù)的事件
myEmitter.on('data', (data) => {
console.log('收到數(shù)據(jù):', data);
});
myEmitter.emit('data', { name: '張三', age: 25 });
// 只觸發(fā)一次的事件
myEmitter.once('once', () => {
console.log('這個(gè)事件只會(huì)觸發(fā)一次');
});
myEmitter.emit('once');
myEmitter.emit('once'); // 不會(huì)觸發(fā)
// 錯(cuò)誤處理
myEmitter.on('error', (error) => {
console.error('發(fā)生錯(cuò)誤:', error.message);
});
myEmitter.emit('error', new Error('這是一個(gè)錯(cuò)誤'));
// 移除事件監(jiān)聽器
const handler = () => {
console.log('這個(gè)監(jiān)聽器會(huì)被移除');
};
myEmitter.on('remove', handler);
myEmitter.emit('remove');
myEmitter.removeListener('remove', handler);
myEmitter.emit('remove'); // 不會(huì)觸發(fā)
// 獲取監(jiān)聽器數(shù)量
console.log('監(jiān)聽器數(shù)量:', myEmitter.listenerCount('event'));
// 獲取所有監(jiān)聽器
console.log('所有監(jiān)聽器:', myEmitter.listeners('event'));5. stream(流處理)
const fs = require('fs');
const { Transform } = require('stream');
// 讀取流
const readStream = fs.createReadStream('input.txt', 'utf8');
readStream.on('data', (chunk) => {
console.log('讀取數(shù)據(jù)塊:', chunk);
});
readStream.on('end', () => {
console.log('讀取完成');
});
readStream.on('error', (error) => {
console.error('讀取錯(cuò)誤:', error);
});
// 寫入流
const writeStream = fs.createWriteStream('output.txt', 'utf8');
writeStream.write('Hello, ');
writeStream.write('Node.js!\n');
writeStream.end('結(jié)束寫入');
writeStream.on('finish', () => {
console.log('寫入完成');
});
writeStream.on('error', (error) => {
console.error('寫入錯(cuò)誤:', error);
});
// 管道流(復(fù)制文件)
const readStream2 = fs.createReadStream('input.txt');
const writeStream2 = fs.createWriteStream('output.txt');
readStream2.pipe(writeStream2);
readStream2.on('end', () => {
console.log('文件復(fù)制完成');
});
// 轉(zhuǎn)換流(大寫轉(zhuǎn)換)
const upperCaseTransform = new Transform({
transform(chunk, encoding, callback) {
this.push(chunk.toString().toUpperCase());
callback();
}
});
fs.createReadStream('input.txt')
.pipe(upperCaseTransform)
.pipe(fs.createWriteStream('uppercase.txt'));
// 壓縮流
const zlib = require('zlib');
const gzip = zlib.createGzip();
fs.createReadStream('input.txt')
.pipe(gzip)
.pipe(fs.createWriteStream('input.txt.gz'));
// 解壓流
const gunzip = zlib.createGunzip();
fs.createReadStream('input.txt.gz')
.pipe(gunzip)
.pipe(fs.createWriteStream('uncompressed.txt'));6. crypto(加密)
const crypto = require('crypto');
// MD5哈希
const hash1 = crypto.createHash('md5').update('Hello, Node.js!').digest('hex');
console.log('MD5:', hash1);
// SHA256哈希
const hash2 = crypto.createHash('sha256').update('Hello, Node.js!').digest('hex');
console.log('SHA256:', hash2);
// HMAC
const hmac = crypto.createHmac('sha256', 'secret-key');
hmac.update('Hello, Node.js!');
console.log('HMAC:', hmac.digest('hex'));
// AES加密
const algorithm = 'aes-256-cbc';
const key = crypto.randomBytes(32);
const iv = crypto.randomBytes(16);
function encrypt(text) {
const cipher = crypto.createCipheriv(algorithm, key, iv);
let encrypted = cipher.update(text, 'utf8', 'hex');
encrypted += cipher.final('hex');
return encrypted;
}
function decrypt(encrypted) {
const decipher = crypto.createDecipheriv(algorithm, key, iv);
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
const original = 'Hello, Node.js!';
const encrypted = encrypt(original);
const decrypted = decrypt(encrypted);
console.log('原文:', original);
console.log('加密:', encrypted);
console.log('解密:', decrypted);
// 生成隨機(jī)數(shù)
const randomBytes = crypto.randomBytes(16).toString('hex');
console.log('隨機(jī)數(shù):', randomBytes);
// 生成UUID
function generateUUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
const r = Math.random() * 16 | 0;
const v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
console.log('UUID:', generateUUID());四、NPM包管理
4.1 NPM基礎(chǔ)命令
# 初始化項(xiàng)目 npm init # 初始化項(xiàng)目(使用默認(rèn)配置) npm init -y # 安裝依賴 npm install # 安裝指定包 npm install package-name # 安裝到生產(chǎn)環(huán)境 npm install package-name --save # 安裝到開發(fā)環(huán)境 npm install package-name --save-dev # 全局安裝 npm install -g package-name # 卸載包 npm uninstall package-name # 更新包 npm update package-name # 查看已安裝的包 npm list # 查看全局安裝的包 npm list -g # 查看包信息 npm info package-name # 搜索包 npm search package-name # 查看過期的包 npm outdated # 清理緩存 npm cache clean --force
4.2 package.json詳解
{
"name": "my-nodejs-app",
"version": "1.0.0",
"description": "我的Node.js應(yīng)用",
"main": "index.js",
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js",
"test": "jest",
"build": "webpack --mode production"
},
"dependencies": {
"express": "^4.18.2",
"mongoose": "^7.0.3",
"dotenv": "^16.0.3"
},
"devDependencies": {
"nodemon": "^2.0.22",
"jest": "^29.5.0",
"webpack": "^5.82.1"
},
"engines": {
"node": ">=16.0.0",
"npm": ">=8.0.0"
},
"author": "張三",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/username/repo.git"
},
"keywords": ["nodejs", "express", "api"]
}4.3 常用NPM包
express - Web框架
npm install express
const express = require('express');
const app = express();
// 中間件
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// 路由
app.get('/', (req, res) => {
res.send('Hello, Express!');
});
app.get('/api/users', (req, res) => {
res.json([
{ id: 1, name: '張三' },
{ id: 2, name: '李四' }
]);
});
app.post('/api/users', (req, res) => {
const user = req.body;
user.id = Date.now();
res.status(201).json(user);
});
app.listen(3000, () => {
console.log('Express服務(wù)器運(yùn)行在 http://localhost:3000');
});nodemon - 自動(dòng)重啟
npm install -D nodemon
{
"scripts": {
"dev": "nodemon index.js"
}
}dotenv - 環(huán)境變量
npm install dotenv
// .env
PORT=3000
DB_HOST=localhost
DB_USER=root
DB_PASS=password
// index.js
require('dotenv').config();
const port = process.env.PORT || 3000;
console.log('服務(wù)器端口:', port);axios - HTTP客戶端
npm install axios
const axios = require('axios');
// GET請求
async function getData() {
try {
const response = await axios.get('https://api.example.com/data');
console.log(response.data);
} catch (error) {
console.error('請求失敗:', error);
}
}
// POST請求
async function postData() {
try {
const response = await axios.post('https://api.example.com/users', {
name: '張三',
age: 25
});
console.log(response.data);
} catch (error) {
console.error('請求失敗:', error);
}
}mongoose - MongoDB ODM
npm install mongoose
const mongoose = require('mongoose');
// 連接數(shù)據(jù)庫
mongoose.connect('mongodb://localhost:27017/mydatabase', {
useNewUrlParser: true,
useUnifiedTopology: true
});
// 定義模型
const UserSchema = new mongoose.Schema({
name: { type: String, required: true },
age: { type: Number, required: true },
email: { type: String, required: true, unique: true }
});
const User = mongoose.model('User', UserSchema);
// 創(chuàng)建用戶
async function createUser() {
const user = new User({
name: '張三',
age: 25,
email: 'zhangsan@example.com'
});
await user.save();
console.log('用戶創(chuàng)建成功:', user);
}
// 查詢用戶
async function findUsers() {
const users = await User.find({ age: { $gte: 20 } });
console.log('查詢結(jié)果:', users);
}
// 更新用戶
async function updateUser(id) {
const user = await User.findByIdAndUpdate(
id,
{ age: 26 },
{ new: true }
);
console.log('用戶更新成功:', user);
}
// 刪除用戶
async function deleteUser(id) {
await User.findByIdAndDelete(id);
console.log('用戶刪除成功');
}五、Express框架詳解
5.1 Express基礎(chǔ)
const express = require('express');
const app = express();
// 中間件配置
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static('public'));
// 路由
app.get('/', (req, res) => {
res.send('Hello, Express!');
});
app.get('/about', (req, res) => {
res.send('關(guān)于我們');
});
// 路由參數(shù)
app.get('/users/:id', (req, res) => {
const userId = req.params.id;
res.send(`用戶ID: ${userId}`);
});
// 查詢參數(shù)
app.get('/search', (req, res) => {
const keyword = req.query.keyword;
res.send(`搜索關(guān)鍵詞: ${keyword}`);
});
// POST請求
app.post('/users', (req, res) => {
const user = req.body;
res.status(201).json(user);
});
// 啟動(dòng)服務(wù)器
app.listen(3000, () => {
console.log('服務(wù)器運(yùn)行在 http://localhost:3000');
});5.2 路由器
const express = require('express');
const router = express.Router();
// 用戶路由
router.get('/', (req, res) => {
res.json([
{ id: 1, name: '張三' },
{ id: 2, name: '李四' }
]);
});
router.get('/:id', (req, res) => {
const userId = req.params.id;
res.json({ id: userId, name: '張三' });
});
router.post('/', (req, res) => {
const user = req.body;
user.id = Date.now();
res.status(201).json(user);
});
router.put('/:id', (req, res) => {
const userId = req.params.id;
const user = req.body;
res.json({ id: userId, ...user });
});
router.delete('/:id', (req, res) => {
const userId = req.params.id;
res.json({ message: `用戶${userId}已刪除` });
});
module.exports = router;
// 在主應(yīng)用中使用
const userRoutes = require('./routes/users');
app.use('/api/users', userRoutes);5.3 中間件
// 日志中間件
const logger = (req, res, next) => {
console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
next();
};
// 認(rèn)證中間件
const auth = (req, res, next) => {
const token = req.headers.authorization;
if (!token) {
return res.status(401).json({ message: '未授權(quán)' });
}
// 驗(yàn)證token
next();
};
// 錯(cuò)誤處理中間件
const errorHandler = (err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ message: '服務(wù)器錯(cuò)誤' });
};
// 使用中間件
app.use(logger);
app.use('/api/protected', auth);
// 錯(cuò)誤處理
app.use(errorHandler);5.4 模板引擎
// 安裝EJS
npm install ejs
// 配置模板引擎
app.set('view engine', 'ejs');
app.set('views', './views');
// 渲染模板
app.get('/', (req, res) => {
res.render('index', {
title: '我的網(wǎng)站',
users: [
{ name: '張三', age: 25 },
{ name: '李四', age: 30 }
]
});
});
// views/index.ejs
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
</head>
<body>
<h1><%= title %></h1>
<ul>
<% users.forEach(user => { %>
<li><%= user.name %> - <%= user.age %>歲</li>
<% }) %>
</ul>
</body>
</html>六、數(shù)據(jù)庫操作
6.1 MongoDB
const mongoose = require('mongoose');
// 連接數(shù)據(jù)庫
mongoose.connect('mongodb://localhost:27017/myapp');
// 定義Schema
const userSchema = new mongoose.Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
age: { type: Number, default: 0 },
createdAt: { type: Date, default: Date.now }
});
// 創(chuàng)建Model
const User = mongoose.model('User', userSchema);
// CRUD操作
// 創(chuàng)建
async function createUser() {
const user = new User({
name: '張三',
email: 'zhangsan@example.com',
age: 25
});
await user.save();
return user;
}
// 讀取
async function getUsers() {
const users = await User.find({ age: { $gte: 18 } })
.sort({ age: -1 })
.limit(10);
return users;
}
async function getUserById(id) {
const user = await User.findById(id);
return user;
}
// 更新
async function updateUser(id, updates) {
const user = await User.findByIdAndUpdate(
id,
updates,
{ new: true, runValidators: true }
);
return user;
}
// 刪除
async function deleteUser(id) {
await User.findByIdAndDelete(id);
}6.2 MySQL
const mysql = require('mysql2/promise');
// 創(chuàng)建連接池
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: 'password',
database: 'myapp',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
// CRUD操作
// 創(chuàng)建
async function createUser(user) {
const sql = 'INSERT INTO users (name, email, age) VALUES (?, ?, ?)';
const [result] = await pool.execute(sql, [user.name, user.email, user.age]);
return result.insertId;
}
// 讀取
async function getUsers() {
const [rows] = await pool.execute('SELECT * FROM users WHERE age >= ?', [18]);
return rows;
}
async function getUserById(id) {
const [rows] = await pool.execute('SELECT * FROM users WHERE id = ?', [id]);
return rows[0];
}
// 更新
async function updateUser(id, updates) {
const sql = 'UPDATE users SET name = ?, email = ?, age = ? WHERE id = ?';
const [result] = await pool.execute(sql, [updates.name, updates.email, updates.age, id]);
return result.affectedRows > 0;
}
// 刪除
async function deleteUser(id) {
const sql = 'DELETE FROM users WHERE id = ?';
const [result] = await pool.execute(sql, [id]);
return result.affectedRows > 0;
}
// 事務(wù)
async function transferMoney(fromId, toId, amount) {
const connection = await pool.getConnection();
try {
await connection.beginTransaction();
// 扣款
await connection.execute(
'UPDATE users SET balance = balance - ? WHERE id = ?',
[amount, fromId]
);
// 加款
await connection.execute(
'UPDATE users SET balance = balance + ? WHERE id = ?',
[amount, toId]
);
await connection.commit();
return true;
} catch (error) {
await connection.rollback();
throw error;
} finally {
connection.release();
}
}七、實(shí)戰(zhàn)項(xiàng)目:RESTful API
7.1 項(xiàng)目結(jié)構(gòu)
my-api/ ├── config/ │ └── database.js ├── models/ │ └── User.js ├── routes/ │ └── users.js ├── middleware/ │ └── auth.js ├── controllers/ │ └── userController.js ├── app.js ├── .env └── package.json
7.2 實(shí)現(xiàn)代碼
// package.json
{
"name": "my-api",
"version": "1.0.0",
"main": "app.js",
"scripts": {
"start": "node app.js",
"dev": "nodemon app.js"
},
"dependencies": {
"express": "^4.18.2",
"mongoose": "^7.0.3",
"dotenv": "^16.0.3",
"bcryptjs": "^2.4.3",
"jsonwebtoken": "^9.0.0"
},
"devDependencies": {
"nodemon": "^2.0.22"
}
}
// .env
PORT=3000
MONGODB_URI=mongodb://localhost:27017/myapi
JWT_SECRET=your-secret-key
// config/database.js
const mongoose = require('mongoose');
const connectDB = async () => {
try {
await mongoose.connect(process.env.MONGODB_URI);
console.log('MongoDB連接成功');
} catch (error) {
console.error('MongoDB連接失敗:', error);
process.exit(1);
}
};
module.exports = connectDB;
// models/User.js
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true,
trim: true
},
email: {
type: String,
required: true,
unique: true,
trim: true,
lowercase: true
},
password: {
type: String,
required: true,
minlength: 6
},
role: {
type: String,
enum: ['user', 'admin'],
default: 'user'
}
}, {
timestamps: true
});
// 密碼加密
userSchema.pre('save', async function(next) {
if (!this.isModified('password')) {
return next();
}
const salt = await bcrypt.genSalt(10);
this.password = await bcrypt.hash(this.password, salt);
next();
});
// 密碼驗(yàn)證
userSchema.methods.comparePassword = async function(candidatePassword) {
return await bcrypt.compare(candidatePassword, this.password);
};
module.exports = mongoose.model('User', userSchema);
// controllers/userController.js
const User = require('../models/User');
const jwt = require('jsonwebtoken');
// 生成JWT
const generateToken = (userId) => {
return jwt.sign({ userId }, process.env.JWT_SECRET, {
expiresIn: '7d'
});
};
// 注冊
exports.register = async (req, res) => {
try {
const { name, email, password } = req.body;
// 檢查用戶是否已存在
const existingUser = await User.findOne({ email });
if (existingUser) {
return res.status(400).json({ message: '郵箱已被注冊' });
}
// 創(chuàng)建用戶
const user = new User({ name, email, password });
await user.save();
// 生成token
const token = generateToken(user._id);
res.status(201).json({
message: '注冊成功',
token,
user: {
id: user._id,
name: user.name,
email: user.email,
role: user.role
}
});
} catch (error) {
res.status(500).json({ message: '服務(wù)器錯(cuò)誤', error: error.message });
}
};
// 登錄
exports.login = async (req, res) => {
try {
const { email, password } = req.body;
// 查找用戶
const user = await User.findOne({ email });
if (!user) {
return res.status(401).json({ message: '郵箱或密碼錯(cuò)誤' });
}
// 驗(yàn)證密碼
const isMatch = await user.comparePassword(password);
if (!isMatch) {
return res.status(401).json({ message: '郵箱或密碼錯(cuò)誤' });
}
// 生成token
const token = generateToken(user._id);
res.json({
message: '登錄成功',
token,
user: {
id: user._id,
name: user.name,
email: user.email,
role: user.role
}
});
} catch (error) {
res.status(500).json({ message: '服務(wù)器錯(cuò)誤', error: error.message });
}
};
// 獲取用戶信息
exports.getProfile = async (req, res) => {
try {
const user = await User.findById(req.userId).select('-password');
if (!user) {
return res.status(404).json({ message: '用戶不存在' });
}
res.json(user);
} catch (error) {
res.status(500).json({ message: '服務(wù)器錯(cuò)誤', error: error.message });
}
};
// 更新用戶信息
exports.updateProfile = async (req, res) => {
try {
const { name, email } = req.body;
const user = await User.findByIdAndUpdate(
req.userId,
{ name, email },
{ new: true, runValidators: true }
).select('-password');
if (!user) {
return res.status(404).json({ message: '用戶不存在' });
}
res.json({ message: '更新成功', user });
} catch (error) {
res.status(500).json({ message: '服務(wù)器錯(cuò)誤', error: error.message });
}
};
// middleware/auth.js
const jwt = require('jsonwebtoken');
const auth = async (req, res, next) => {
try {
const token = req.header('Authorization')?.replace('Bearer ', '');
if (!token) {
return res.status(401).json({ message: '未提供認(rèn)證token' });
}
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.userId = decoded.userId;
next();
} catch (error) {
res.status(401).json({ message: '無效的token' });
}
};
module.exports = auth;
// routes/users.js
const express = require('express');
const router = express.Router();
const { register, login, getProfile, updateProfile } = require('../controllers/userController');
const auth = require('../middleware/auth');
router.post('/register', register);
router.post('/login', login);
router.get('/profile', auth, getProfile);
router.put('/profile', auth, updateProfile);
module.exports = router;
// app.js
require('dotenv').config();
const express = require('express');
const connectDB = require('./config/database');
const userRoutes = require('./routes/users');
const app = express();
// 連接數(shù)據(jù)庫
connectDB();
// 中間件
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// 路由
app.use('/api/users', userRoutes);
// 錯(cuò)誤處理
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ message: '服務(wù)器錯(cuò)誤' });
});
// 啟動(dòng)服務(wù)器
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`服務(wù)器運(yùn)行在 http://localhost:${PORT}`);
});八、Node.js最佳實(shí)踐
8.1 錯(cuò)誤處理
// 使用異步函數(shù)和try-catch
async function asyncOperation() {
try {
const result = await someAsyncOperation();
return result;
} catch (error) {
console.error('操作失敗:', error);
throw error;
}
}
// 錯(cuò)誤處理中間件
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({
message: '服務(wù)器錯(cuò)誤',
error: process.env.NODE_ENV === 'development' ? err.message : {}
});
});
// 未捕獲的Promise拒絕
process.on('unhandledRejection', (reason, promise) => {
console.error('未處理的Promise拒絕:', reason);
});
// 未捕獲的異常
process.on('uncaughtException', (error) => {
console.error('未捕獲的異常:', error);
process.exit(1);
});8.2 安全性
// 使用helmet
const helmet = require('helmet');
app.use(helmet());
// 使用cors
const cors = require('cors');
app.use(cors());
// 輸入驗(yàn)證
const { body, validationResult } = require('express-validator');
app.post('/users', [
body('name').notEmpty().withMessage('姓名不能為空'),
body('email').isEmail().withMessage('郵箱格式不正確'),
body('password').isLength({ min: 6 }).withMessage('密碼至少6位')
], (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// 處理請求
});
// 環(huán)境變量
require('dotenv').config();
// 限制請求頻率
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15分鐘
max: 100 // 限制100次請求
});
app.use(limiter);8.3 性能優(yōu)化
// 啟用Gzip壓縮
const compression = require('compression');
app.use(compression());
// 使用緩存
const NodeCache = require('node-cache');
const cache = new NodeCache({ stdTTL: 600 }); // 10分鐘緩存
app.get('/api/data', async (req, res) => {
const cacheKey = 'data';
const cachedData = cache.get(cacheKey);
if (cachedData) {
return res.json(cachedData);
}
const data = await fetchData();
cache.set(cacheKey, data);
res.json(data);
});
// 使用連接池
const pool = mysql.createPool({
connectionLimit: 10,
// 其他配置
});
// 使用集群(多進(jìn)程)
const cluster = require('cluster');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
} else {
// 啟動(dòng)服務(wù)器
app.listen(3000);
}8.4 日志記錄
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' })
]
});
if (process.env.NODE_ENV !== 'production') {
logger.add(new winston.transports.Console({
format: winston.format.simple()
}));
}
// 使用日志
logger.info('服務(wù)器啟動(dòng)');
logger.error('發(fā)生錯(cuò)誤', error);九、部署和運(yùn)維
9.1 PM2進(jìn)程管理
# 安裝PM2 npm install -g pm2 # 啟動(dòng)應(yīng)用 pm2 start app.js # 啟動(dòng)應(yīng)用并指定名稱 pm2 start app.js --name my-app # 列出所有進(jìn)程 pm2 list # 查看日志 pm2 logs # 重啟應(yīng)用 pm2 restart my-app # 停止應(yīng)用 pm2 stop my-app # 刪除應(yīng)用 pm2 delete my-app # 監(jiān)控 pm2 monit # 保存進(jìn)程列表 pm2 save # 設(shè)置開機(jī)自啟 pm2 startup
9.2 Docker容器化
# Dockerfile FROM node:18-alpine WORKDIR /app COPY package*.json ./ RUN npm install --production COPY . . EXPOSE 3000 CMD ["node", "app.js"]
# 構(gòu)建鏡像 docker build -t my-nodejs-app . # 運(yùn)行容器 docker run -p 3000:3000 my-nodejs-app
# docker-compose.yml
version: '3'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- MONGODB_URI=mongodb://mongo:27017/myapp
depends_on:
- mongo
mongo:
image: mongo:latest
ports:
- "27017:27017"
volumes:
- mongo-data:/data/db
volumes:
mongo-data:# 使用docker-compose啟動(dòng) docker-compose up -d
十、總結(jié)
Node.js是一個(gè)功能強(qiáng)大、生態(tài)豐富的后端開發(fā)平臺(tái)。通過本文的學(xué)習(xí),你應(yīng)該掌握了:
- Node.js的基礎(chǔ)概念和安裝配置
- 模塊系統(tǒng)(CommonJS和ES6)
- 核心模塊的使用(fs、http、path、events等)
- NPM包管理和常用包
- Express框架的詳細(xì)使用
- 數(shù)據(jù)庫操作(MongoDB、MySQL)
- 完整的RESTful API項(xiàng)目實(shí)戰(zhàn)
- Node.js最佳實(shí)踐(錯(cuò)誤處理、安全性、性能優(yōu)化)
- 部署和運(yùn)維(PM2、Docker)
學(xué)習(xí)建議:
- 多動(dòng)手實(shí)踐,創(chuàng)建自己的項(xiàng)目
- 深入理解Node.js的異步編程模型
- 學(xué)習(xí)TypeScript提高代碼質(zhì)量
- 關(guān)注Node.js的最新發(fā)展
- 參與開源項(xiàng)目,學(xué)習(xí)優(yōu)秀的代碼
- 掌握監(jiān)控和調(diào)試技巧
Node.js的學(xué)習(xí)是一個(gè)持續(xù)的過程,隨著技術(shù)的發(fā)展,Node.js也在不斷進(jìn)化。保持學(xué)習(xí)的熱情,不斷提升自己的技能,你一定能成為一名優(yōu)秀的Node.js開發(fā)者!
希望這篇Node.js詳解教程對你有所幫助!如果你有任何問題或建議,歡迎留言討論。持續(xù)學(xué)習(xí),不斷進(jìn)步,讓我們一起在后端開發(fā)的道路上越走越遠(yuǎn)!
到此這篇關(guān)于Node.js完全指南:從入門到精通的文章就介紹到這了,更多相關(guān)Node.js從入門到精通內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Node.js基礎(chǔ)入門之回調(diào)函數(shù)及異步與同步詳解
Node.js是一個(gè)基于Chrome?V8引擎的JavaScript運(yùn)行時(shí)。類似于Java中的JRE,.Net中的CLR。本文將詳細(xì)為大家介紹Node.js中的回調(diào)函數(shù)及異步與同步,感興趣的可以了解一下2022-03-03
基于Node.js實(shí)現(xiàn)數(shù)據(jù)轉(zhuǎn)換工具
在前端項(xiàng)目中,利用?Excel?表格和?Node.js?實(shí)現(xiàn)數(shù)據(jù)轉(zhuǎn)換工具,可以有效優(yōu)化增刪改查等功能,下面小編就來和大家講講具體的實(shí)現(xiàn)步驟吧2025-02-02
如何正確使用Nodejs 的 c++ module 鏈接到 OpenSSL
這篇文章主要介紹了如何正確使用Nodejs 的 c++ module 鏈接到 OpenSSL,需要的朋友可以參考下2014-08-08
從零學(xué)習(xí)node.js之詳解異步控制工具async(八)
sync是一個(gè)流程控制工具包,提供了直接而強(qiáng)大的異步功能。基于JavaScript為Node.js設(shè)計(jì),同時(shí)也可以直接在瀏覽器中使用。下面這篇文章主要介紹了node.js之異步控制工具async的相關(guān)資料,需要的朋友可以參考下。2017-02-02
Ubuntu22.04系統(tǒng)下升級(jí)nodejs到v18版本
ubuntu默認(rèn)安裝的nodejs版本比較老,要安裝到最新的,下面這篇文章主要給大家介紹了關(guān)于Ubuntu22.04系統(tǒng)下升級(jí)nodejs到v18版本的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-06-06
詳解基于Koa2開發(fā)微信二維碼掃碼支付相關(guān)流程
這篇文章主要介紹了詳解基于Koa2開發(fā)微信二維碼掃碼支付相關(guān)流程,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-05-05

