mcpField
N
nodejs-development

nodejs-development

github.com/manutej开发1196 次安装49 周前更新
代码仓库

关于 nodejs-development

nodejs-development 是一项面向 Node.js 开发者的综合指导技能,涵盖应用构建所需的核心概念、示例与实践。内容涉及异步处理、流、HTTP 服务以及安全、测试和部署等主题。

主要功能

  1. 01事件循环与模块系统
  2. 02异步模式、流和文件操作
  3. 03HTTP、进程与环境管理
  4. 04REST API 和数据库工作模式
  5. 05安全、测试、日志与部署实践

适用场景

  1. 01构建 REST API 与后端服务
  2. 02开发 CLI 工具或自动化脚本
  3. 03处理实时通信、文件转换或后台任务

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/manutej/crush-mcp-server --skill nodejs-development

安装后在 Claude Code 中输入/nodejs-development确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

EXAMPLES.md
README.md
nodejs-development/
EXAMPLES.md
README.md

详细介绍

Node.js 开发技能

此技能提供全面的指导,涵盖事件循环、异步模式、流、文件系统操作、HTTP 服务、进程管理,以及构建可用于生产环境的 Node.js 应用的最佳实践。

何时使用此技能

在以下场景中使用此技能:

  • 构建 RESTful API 和后端服务
  • 创建命令行界面(CLI)工具和实用程序
  • 开发微服务和分布式系统
  • 使用 WebSocket 或 Server-Sent Events 构建实时应用
  • 创建构建工具、任务运行器和开发工具
  • 处理文件和数据转换
  • 实现服务端数据验证和业务逻辑
  • 构建代理服务和中间件层
  • 创建自动化脚本和系统实用程序
  • 开发无服务器函数和云原生应用
  • 实现后台作业处理器和工作进程
  • 构建 GraphQL 服务和 API 网关

核心概念

事件循环

事件循环是 Node.js 的核心,它让 JavaScript 即使在单线程运行的情况下,也能执行非阻塞 I/O 操作。

事件循环阶段:

// The event loop processes operations in this order:
// 1. Timers (setTimeout, setInterval)
// 2. Pending callbacks (I/O callbacks deferred from previous iteration)
// 3. Idle, prepare (internal use)
// 4. Poll (retrieve new I/O events)
// 5. Check (setImmediate callbacks)
// 6. Close callbacks (socket.on('close'))

// Understanding execution order
console.log('1 - Start');

setTimeout(() => {
  console.log('2 - Timeout');
}, 0);

setImmediate(() => {
  console.log('3 - Immediate');
});

Promise.resolve().then(() => {
  console.log('4 - Promise');
});

process.nextTick(() => {
  console.log('5 - Next Tick');
});

console.log('6 - End');

// Output order: 1, 6, 5, 4, 2, 3
// (process.nextTick and Promises run before other phases)

事件循环最佳实践:

// Don't block the event loop
// Bad - blocking operation
const data = fs.readFileSync('large-file.txt'); // Blocks

// Good - non-blocking
fs.readFile('large-file.txt', (err, data) => {
  // Non-blocking
});

// Better - using promises
const data = await fs.promises.readFile('large-file.txt');

// Avoid heavy CPU operations
// Bad - blocks event loop
function fibonacci(n) {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

// Good - offload to worker threads
const { Worker } = require('worker_threads');

function computeInWorker(n) {
  return new Promise((resolve, reject) => {
    const worker = new Worker('./fibonacci-worker.js', {
      workerData: n
    });
    worker.on('message', resolve);
    worker.on('error', reject);
  });
}
模块

Node.js 支持 CommonJS 和 ES 模块,用于组织代码。

CommonJS(传统方式):

// math.js - Exporting
function add(a, b) {
  return a + b;
}

function subtract(a, b) {
  return a - b;
}

module.exports = { add, subtract };

// Alternative export syntax
exports.multiply = (a, b) => a * b;

// app.js - Importing
const { add, subtract } = require('./math');
const fs = require('fs'); // Built-in module
const express = require('express'); // npm package

console.log(add(5, 3)); // 8

ES 模块(现代方式):

// math.mjs or math.js (with "type": "module" in package.json)
export function add(a, b) {
  return a + b;
}

export function subtract(a, b) {
  return a - b;
}

export default class Calculator {
  add(a, b) { return a + b; }
}

// app.mjs - Importing
import { add, subtract } from './math.mjs';
import Calculator from './math.mjs';
import fs from 'fs';
import express from 'express';

console.log(add(5, 3)); // 8

内置模块:

// Core Node.js modules (no npm install required)
const fs = require('fs');           // File system
const path = require('path');       // Path utilities
const http = require('http');       // HTTP server
const https = require('https');     // HTTPS server
const crypto = require('crypto');   // Cryptography
const os = require('os');           // Operating system
const events = require('events');   // Event emitter
const stream = require('stream');   // Streams
const util = require('util');       // Utilities
const child_process = require('child_process'); // Child processes
const cluster = require('cluster'); // Clustering
const url = require('url');         // URL parsing
const querystring = require('querystring'); // Query strings
异步编程

Node.js 提供多种处理异步操作的模式。

回调(传统方式):

const fs = require('fs');

// Error-first callback pattern
fs.readFile('file.txt', 'utf8', (err, data) => {
  if (err) {
    console.error('Error reading file:', err);
    return;
  }
  console.log('File contents:', data);
});

// Callback hell (avoid this)
fs.readFile('file1.txt', (err, data1) => {
  if (err) return console.error(err);
  fs.readFile('file2.txt', (err, data2) => {
    if (err) return console.error(err);
    fs.readFile('file3.txt', (err, data3) => {
      if (err) return console.error(err);
      console.log(data1, data2, data3);
    });
  });
});

Promise:

const fs = require('fs').promises;

// Basic promise
fs.readFile('file.txt', 'utf8')
  .then(data => {
    console.log('File contents:', data);
    return data;
  })
  .catch(err => {
    console.error('Error:', err);
  })
  .finally(() => {
    console.log('Operation complete');
  });

// Promise chaining
fs.readFile('file1.txt', 'utf8')
  .then(data1 => {
    console.log('File 1:', data1);
    return fs.readFile('file2.txt', 'utf8');
  })
  .then(data2 => {
    console.log('File 2:', data2);
    return fs.readFile('file3.txt', 'utf8');
  })
  .then(data3 => {
    console.log('File 3:', data3);
  })
  .catch(err => {
    console.error('Error:', err);
  });

// Promise.all for parallel operations
Promise.all([
  fs.readFile('file1.txt', 'utf8'),
  fs.readFile('file2.txt', 'utf8'),
  fs.readFile('file3.txt', 'utf8')
])
  .then(([data1, data2, data3]) => {
    console.log(data1, data2, data3);
  })
  .catch(err => {
    console.error('Error:', err);
  });

// Promise utilities
Promise.race([
  fetch('https://api1.com'),
  fetch('https://api2.com')
]); // Returns first to complete

Promise.allSettled([
  promise1,
  promise2,
  promise3
]); // Waits for all, returns all results (success or failure)

Promise.any([
  promise1,
  promise2
]); // Returns first successful promise

Async/Await(现代方式):

const fs = require('fs').promises;

// Basic async/await
async function readFile() {
  try {
    const data = await fs.readFile('file.txt', 'utf8');
    console.log('File contents:', data);
    return data;
  } catch (err) {
    console.error('Error:', err);
    throw err;
  }
}

// Sequential execution
async function readFilesSequentially() {
  try {
    const data1 = await fs.readFile('file1.txt', 'utf8');
    const data2 = await fs.readFile('file2.txt', 'utf8');
    const data3 = await fs.readFile('file3.txt', 'utf8');
    return [data1, data2, data3];
  } catch (err) {
    console.error('Error:', err);
    throw err;
  }
}

// Parallel execution
async function readFilesParallel() {
  try {
    const [data1, data2, data3] = await Promise.all([
      fs.readFile('file1.txt', 'utf8'),
      fs.readFile('file2.txt', 'utf8'),
      fs.readFile('file3.txt', 'utf8')
    ]);
    return [data1, data2, data3];
  } catch (err) {
    console.error('Error:', err);
    throw err;
  }
}

// Top-level await (ES modules only)
const data = await fs.readFile('config.json', 'utf8');
const config = JSON.parse(data);

// Error handling patterns
async function robustOperation() {
  try {
    const result = await riskyOperation();
    return { success: true, data: result };
  } catch (err) {
    console.error('Operation failed:', err);
    return { success: false, error: err.message };
  }
}

// Multiple error handling
async function multipleOperations() {
  const results = await Promise.allSettled([
    operation1(),
    operation2(),
    operation3()
  ]);

  results.forEach((result, index) => {
    if (result.status === 'fulfilled') {
      console.log(`Operation ${index} succeeded:`, result.value);
    } else {
      console.error(`Operation ${index} failed:`, result.reason);
    }
  });
}

Promisify 工具:

const util = require('util');
const fs = require('fs');

// Convert callback-based function to promise-based
const readFile = util.promisify(fs.readFile);
const writeFile = util.promisify(fs.writeFile);

async function processFile() {
  const data = await readFile('input.txt', 'utf8');
  const processed = data.toUpperCase();
  await writeFile('output.txt', processed);
}

// Custom promisify
function promisify(fn) {
  return (...args) => {
    return new Promise((resolve, reject) => {
      fn(...args, (err, result) => {
        if (err) reject(err);
        else resolve(result);
      });
    });
  };
}
流

流是 Node.js 中用于高效处理数据的最强大功能之一。

流类型:

const fs = require('fs');
const { Readable, Writable, Duplex, Transform } = require('stream');

// 1. Readable Stream
const readStream = fs.createReadStream('large-file.txt', {
  encoding: 'utf8',
  highWaterMark: 64 * 1024 // 64KB chunks
});

readStream.on('data', (chunk) => {
  console.log('Received chunk:', chunk.length);
});

readStream.on('end', () => {
  console.log('Finished reading');
});

readStream.on('error', (err) => {
  console.error('Error:', err);
});

// 2. Writable Stream
const writeStream = fs.createWriteStream('output.txt');

writeStream.write('Hello ');
writeStream.write('World\n');
writeStream.end();

writeStream.on('finish', () => {
  console.log('Finished writing');
});

// 3. Pipe - connecting streams
fs.createReadStream('input.txt')
  .pipe(fs.createWriteStream('output.txt'));

// 4. Transform Stream
class UpperCaseTransform extends Transform {
  _transform(chunk, encoding, callback) {
    this.push(chunk.toString().toUpperCase());
    callback();
  }
}

fs.createReadStream('input.txt')
  .pipe(new UpperCaseTransform())
  .pipe(fs.createWriteStream('output.txt'));

// 5. Custom Readable Stream
class NumberStream extends Readable {
  constructor(max) {
    super();
    this.current = 0;
    this.max = max;
  }

  _read() {
    if (this.current <= this.max) {
      this.push(String(this.current++));
    } else {
      this.push(null); // End stream
    }
  }
}

const numberStream = new NumberStream(10);
numberStream.on('data', (num) => {
  console.log(num);
});

// 6. Custom Writable Stream
class LogStream extends Writable {
  _write(chunk, encoding, callback) {
    console.log(`[LOG] ${chunk.toString()}`);
    callback();
  }
}

const logStream = new LogStream();
logStream.write('Message 1\n');
logStream.write('Message 2\n');

流模式:

const { pipeline } = require('stream');
const { createReadStream, createWriteStream } = require('fs');
const { createGzip } = require('zlib');

// Pipeline - handles errors and cleanup automatically
pipeline(
  createReadStream('input.txt'),
  createGzip(),
  createWriteStream('input.txt.gz'),
  (err) => {
    if (err) {
      console.error('Pipeline failed:', err);
    } else {
      console.log('Pipeline succeeded');
    }
  }
);

// Stream utilities
const { finished, pipeline: promisePipeline } = require('stream/promises');

async function processFile() {
  await promisePipeline(
    createReadStream('input.txt'),
    createGzip(),
    createWriteStream('output.txt.gz')
  );
  console.log('Processing complete');
}

// Backpressure handling
const reader = createReadStream('large-file.txt');
const writer = createWriteStream('output.txt');

reader.on('data', (chunk) => {
  const canContinue = writer.write(chunk);
  if (!canContinue) {
    // Pause reading if write buffer is full
    reader.pause();
  }
});

writer.on('drain', () => {
  // Resume reading when write buffer is drained
  reader.resume();
});
文件系统

fs 模块提供文件系统操作功能。

读取文件:

const fs = require('fs');
const fsPromises = require('fs').promises;

// Synchronous (blocking - avoid in production)
try {
  const data = fs.readFileSync('file.txt', 'utf8');
  console.log(data);
} catch (err) {
  console.error(err);
}

// Callback-based
fs.readFile('file.txt', 'utf8', (err, data) => {
  if (err) {
    console.error('Error reading file:', err);
    return;
  }
  console.log(data);
});

// Promise-based
fsPromises.readFile('file.txt', 'utf8')
  .then(data => console.log(data))
  .catch(err => console.error(err));

// Async/await
async function readFile() {
  try {
    const data = await fsPromises.readFile('file.txt', 'utf8');
    console.log(data);
  } catch (err) {
    console.error('Error:', err);
  }
}

// Read JSON file
async function readJSON(filename) {
  const data = await fsPromises.readFile(filename, 'utf8');
  return JSON.parse(data);
}

写入文件:

// Write file (overwrites if exists)
await fsPromises.writeFile('output.txt', 'Hello World');

// Append to file
await fsPromises.appendFile('log.txt', 'New log entry\n');

// Write JSON
async function writeJSON(filename, data) {
  await fsPromises.writeFile(
    filename,
    JSON.stringify(data, null, 2)
  );
}

// Atomic write (write to temp, then rename)
async function atomicWrite(filename, data) {
  const tempFile = `${filename}.tmp`;
  await fsPromises.writeFile(tempFile, data);
  await fsPromises.rename(tempFile, filename);
}

文件操作:

const path = require('path');

// Check if file exists
async function fileExists(filename) {
  try {
    await fsPromises.access(filename);
    return true;
  } catch {
    return false;
  }
}

// Get file stats
const stats = await fsPromises.stat('file.txt');
console.log({
  size: stats.size,
  isFile: stats.isFile(),
  isDirectory: stats.isDirectory(),
  modified: stats.mtime,
  created: stats.birthtime
});

// Copy file
await fsPromises.copyFile('source.txt', 'dest.txt');

// Move/rename file
await fsPromises.rename('old-name.txt', 'new-name.txt');

// Delete file
await fsPromises.unlink('file-to-delete.txt');

// Create directory
await fsPromises.mkdir('new-directory', { recursive: true });

// Read directory
const files = await fsPromises.readdir('directory');
console.log(files);

// Read directory with file types
const entries = await fsPromises.readdir('directory', {
  withFileTypes: true
});

for (const entry of entries) {
  if (entry.isFile()) {
    console.log('File:', entry.name);
  } else if (entry.isDirectory()) {
    console.log('Directory:', entry.name);
  }
}

// Remove directory
await fsPromises.rmdir('directory');

// Remove directory recursively
await fsPromises.rm('directory', { recursive: true, force: true });

// Watch for file changes
const watcher = fs.watch('file.txt', (eventType, filename) => {
  console.log(`File ${filename} changed: ${eventType}`);
});

// Stop watching
watcher.close();

路径实用工具:

const path = require('path');

// Join paths (handles separators correctly)
const fullPath = path.join('/users', 'john', 'documents', 'file.txt');
// /users/john/documents/file.txt

// Resolve absolute path
const absolute = path.resolve('documents', 'file.txt');
// /current/working/directory/documents/file.txt

// Get directory name
path.dirname('/users/john/file.txt'); // /users/john

// Get file name
path.basename('/users/john/file.txt'); // file.txt
path.basename('/users/john/file.txt', '.txt'); // file

// Get extension
path.extname('file.txt'); // .txt

// Parse path
const parsed = path.parse('/users/john/file.txt');
// {
//   root: '/',
//   dir: '/users/john',
//   base: 'file.txt',
//   ext: '.txt',
//   name: 'file'
// }

// Format path
const formatted = path.format({
  dir: '/users/john',
  base: 'file.txt'
}); // /users/john/file.txt

// Normalize path
path.normalize('/users/john/../jane/./file.txt');
// /users/jane/file.txt

// Check if absolute
path.isAbsolute('/users/john'); // true
path.isAbsolute('documents/file.txt'); // false

// Get relative path
path.relative('/users/john', '/users/jane/file.txt');
// ../jane/file.txt
HTTP/HTTPS

创建 HTTP 服务并发送 HTTP 请求。

HTTP 服务:

const http = require('http');

// Basic HTTP server
const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World\n');
});

server.listen(3000, () => {
  console.log('Server running at http://localhost:3000/');
});

// Server with routing
const server = http.createServer((req, res) => {
  const { method, url } = req;

  if (url === '/' && method === 'GET') {
    res.writeHead(200, { 'Content-Type': 'text/html' });
    res.end('<h1>Home Page</h1>');
  } else if (url === '/api/users' && method === 'GET') {
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ users: ['Alice', 'Bob'] }));
  } else if (url === '/api/users' && method === 'POST') {
    let body = '';
    req.on('data', chunk => {
      body += chunk.toString();
    });
    req.on('end', () => {
      const data = JSON.parse(body);
      res.writeHead(201, { 'Content-Type': 'application/json' });
      res.end(JSON.stringify({ success: true, data }));
    });
  } else {
    res.writeHead(404, { 'Content-Type': 'text/plain' });
    res.end('Not Found');
  }
});

server.listen(3000);

// JSON API server
const server = http.createServer(async (req, res) => {
  try {
    if (req.url === '/api/data' && req.method === 'GET') {
      const data = { message: 'Hello', timestamp: Date.now() };
      res.writeHead(200, { 'Content-Type': 'application/json' });
      res.end(JSON.stringify(data));
    } else if (req.url === '/api/data' && req.method === 'POST') {
      const body = await getRequestBody(req);
      const data = JSON.parse(body);

      // Process data
      const result = { received: data, processed: true };

      res.writeHead(201, { 'Content-Type': 'application/json' });
      res.end(JSON.stringify(result));
    } else {
      res.writeHead(404);
      res.end(JSON.stringify({ error: 'Not found' }));
    }
  } catch (err) {
    res.writeHead(500);
    res.end(JSON.stringify({ error: err.message }));
  }
});

function getRequestBody(req) {
  return new Promise((resolve, reject) => {
    let body = '';
    req.on('data', chunk => {
      body += chunk.toString();
    });
    req.on('end', () => resolve(body));
    req.on('error', reject);
  });
}

HTTPS 服务:

const https = require('https');
const fs = require('fs');

const options = {
  key: fs.readFileSync('private-key.pem'),
  cert: fs.readFileSync('certificate.pem')
};

const server = https.createServer(options, (req, res) => {
  res.writeHead(200);
  res.end('Secure Hello World\n');
});

server.listen(443);

发送 HTTP 请求:

const https = require('https');

// Basic GET request
https.get('https://api.example.com/data', (res) => {
  let data = '';

  res.on('data', (chunk) => {
    data += chunk;
  });

  res.on('end', () => {
    console.log(JSON.parse(data));
  });
}).on('error', (err) => {
  console.error('Error:', err.message);
});

// POST request
const postData = JSON.stringify({ name: 'John', age: 30 });

const options = {
  hostname: 'api.example.com',
  port: 443,
  path: '/users',
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Content-Length': Buffer.byteLength(postData)
  }
};

const req = https.request(options, (res) => {
  let data = '';

  res.on('data', (chunk) => {
    data += chunk;
  });

  res.on('end', () => {
    console.log('Response:', JSON.parse(data));
  });
});

req.on('error', (err) => {
  console.error('Error:', err.message);
});

req.write(postData);
req.end();

// Promise wrapper for HTTP requests
function httpRequest(url, options = {}) {
  return new Promise((resolve, reject) => {
    const req = https.request(url, options, (res) => {
      let data = '';

      res.on('data', (chunk) => {
        data += chunk;
      });

      res.on('end', () => {
        resolve({
          statusCode: res.statusCode,
          headers: res.headers,
          body: data
        });
      });
    });

    req.on('error', reject);

    if (options.body) {
      req.write(options.body);
    }

    req.end();
  });
}

// Using fetch (Node.js 18+)
async function fetchData() {
  const response = await fetch('https://api.example.com/data');
  const data = await response.json();
  console.log(data);
}

async function postData() {
  const response = await fetch('https://api.example.com/users', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ name: 'John', age: 30 })
  });
  const result = await response.json();
  console.log(result);
}
进程和环境

管理进程生命周期和环境变量。

Process 对象:

// Process information
console.log('Node version:', process.version);
console.log('Platform:', process.platform);
console.log('Architecture:', process.arch);
console.log('Process ID:', process.pid);
console.log('Current directory:', process.cwd());
console.log('Memory usage:', process.memoryUsage());
console.log('CPU usage:', process.cpuUsage());
console.log('Uptime:', process.uptime());

// Command-line arguments
// node app.js --port 3000 --host localhost
console.log('Arguments:', process.argv);
// ['node', '/path/to/app.js', '--port', '3000', '--host', 'localhost']

// Parse arguments
function parseArgs() {
  const args = {};
  for (let i = 2; i < process.argv.length; i += 2) {
    const key = process.argv[i].replace('--', '');
    const value = process.argv[i + 1];
    args[key] = value;
  }
  return args;
}

const config = parseArgs();
console.log(config); // { port: '3000', host: 'localhost' }

// Environment variables
const port = process.env.PORT || 3000;
const nodeEnv = process.env.NODE_ENV || 'development';
const dbUrl = process.env.DATABASE_URL;

console.log('Port:', port);
console.log('Environment:', nodeEnv);

// Set environment variable
process.env.MY_VAR = 'value';

// Exit process
process.exit(0); // Success
process.exit(1); // Error

// Exit codes
const EXIT_CODES = {
  SUCCESS: 0,
  GENERAL_ERROR: 1,
  INVALID_ARGUMENT: 2,
  CONFIG_ERROR: 3
};

if (!config.isValid) {
  console.error('Invalid configuration');
  process.exit(EXIT_CODES.CONFIG_ERROR);
}

// Process events
process.on('exit', (code) => {
  console.log(`Process exiting with code ${code}`);
});

process.on('uncaughtException', (err) => {
  console.error('Uncaught exception:', err);
  process.exit(1);
});

process.on('unhandledRejection', (reason, promise) => {
  console.error('Unhandled rejection:', reason);
  process.exit(1);
});

process.on('SIGTERM', () => {
  console.log('SIGTERM received, shutting down gracefully');
  server.close(() => {
    process.exit(0);
  });
});

process.on('SIGINT', () => {
  console.log('SIGINT received, shutting down gracefully');
  process.exit(0);
});

// Send signals to process
process.kill(process.pid, 'SIGTERM');

子进程:

const { exec, execFile, spawn, fork } = require('child_process');

// exec - run shell command
exec('ls -la', (err, stdout, stderr) => {
  if (err) {
    console.error('Error:', err);
    return;
  }
  console.log('Output:', stdout);
  console.error('Errors:', stderr);
});

// execFile - run executable directly (safer)
execFile('node', ['--version'], (err, stdout, stderr) => {
  if (err) {
    console.error('Error:', err);
    return;
  }
  console.log('Node version:', stdout);
});

// spawn - for long-running processes or large output
const ls = spawn('ls', ['-la', '/usr']);

ls.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`);
});

ls.stderr.on('data', (data) => {
  console.error(`stderr: ${data}`);
});

ls.on('close', (code) => {
  console.log(`Process exited with code ${code}`);
});

// fork - spawn Node.js processes
// parent.js
const child = fork('./child.js');

child.on('message', (msg) => {
  console.log('Message from child:', msg);
});

child.send({ hello: 'child' });

// child.js
process.on('message', (msg) => {
  console.log('Message from parent:', msg);
});

process.send({ hello: 'parent' });

// Promise-based exec
const util = require('util');
const execPromise = util.promisify(exec);

async function runCommand() {
  try {
    const { stdout, stderr } = await execPromise('ls -la');
    console.log('Output:', stdout);
  } catch (err) {
    console.error('Error:', err);
  }
}

Cluster 模块:

const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
  console.log(`Master process ${process.pid} is running`);

  // Fork workers
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', (worker, code, signal) => {
    console.log(`Worker ${worker.process.pid} died`);
    // Restart worker
    cluster.fork();
  });
} else {
  // Workers share the same port
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end(`Process ${process.pid} handled request\n`);
  }).listen(8000);

  console.log(`Worker ${process.pid} started`);
}

API 参考

Buffer

Buffer 用于处理 Node.js 中的二进制数据。

// Create buffers
const buf1 = Buffer.from('Hello World');
const buf2 = Buffer.from([72, 101, 108, 108, 111]);
const buf3 = Buffer.alloc(10); // 10 bytes, filled with 0
const buf4 = Buffer.allocUnsafe(10); // Faster, but may contain old data

// Read/write buffers
buf3.write('Hello');
console.log(buf3.toString()); // Hello
console.log(buf3.toString('hex')); // Hex representation

// Buffer operations
const buf5 = Buffer.concat([buf1, buf2]);
const buf6 = buf1.slice(0, 5); // Hello

// Buffer comparison
Buffer.compare(buf1, buf2); // -1, 0, or 1

// JSON conversion
const json = JSON.stringify(buf1);
const parsed = Buffer.from(JSON.parse(json));
事件

EventEmitter 是 Node.js 事件驱动架构的基础。

const EventEmitter = require('events');

// Create event emitter
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();

// Listen for events
myEmitter.on('event', (arg1, arg2) => {
  console.log('Event occurred:', arg1, arg2);
});

// Emit events
myEmitter.emit('event', 'arg1', 'arg2');

// Listen once
myEmitter.once('oneTime', () => {
  console.log('This will only fire once');
});

// Remove listener
function handler() {
  console.log('Handler called');
}

myEmitter.on('event', handler);
myEmitter.off('event', handler);

// Error handling
myEmitter.on('error', (err) => {
  console.error('Error occurred:', err);
});

// Real-world example: Custom logger
class Logger extends EventEmitter {
  log(message) {
    this.emit('log', { message, timestamp: Date.now() });
  }

  error(message) {
    this.emit('error', { message, timestamp: Date.now() });
  }
}

const logger = new Logger();

logger.on('log', (data) => {
  console.log(`[${new Date(data.timestamp).toISOString()}] ${data.message}`);
});

logger.on('error', (data) => {
  console.error(`[${new Date(data.timestamp).toISOString()}] ERROR: ${data.message}`);
});

logger.log('Application started');
logger.error('Something went wrong');
Crypto

用于安全保障的加密操作。

const crypto = require('crypto');

// Generate random data
const randomBytes = crypto.randomBytes(16).toString('hex');
console.log('Random:', randomBytes);

// Hash data (one-way)
const hash = crypto.createHash('sha256');
hash.update('password123');
console.log('Hash:', hash.digest('hex'));

// HMAC (keyed hash)
const hmac = crypto.createHmac('sha256', 'secret-key');
hmac.update('message');
console.log('HMAC:', hmac.digest('hex'));

// Password hashing with salt
function hashPassword(password) {
  const salt = crypto.randomBytes(16).toString('hex');
  const hash = crypto.pbkdf2Sync(password, salt, 100000, 64, 'sha512').toString('hex');
  return { salt, hash };
}

function verifyPassword(password, salt, hash) {
  const hashToVerify = crypto.pbkdf2Sync(password, salt, 100000, 64, 'sha512').toString('hex');
  return hash === hashToVerify;
}

const { salt, hash } = hashPassword('mypassword');
console.log(verifyPassword('mypassword', salt, hash)); // true

// Encryption/Decryption
function encrypt(text, key) {
  const iv = crypto.randomBytes(16);
  const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key), iv);
  let encrypted = cipher.update(text);
  encrypted = Buffer.concat([encrypted, cipher.final()]);
  return iv.toString('hex') + ':' + encrypted.toString('hex');
}

function decrypt(text, key) {
  const parts = text.split(':');
  const iv = Buffer.from(parts[0], 'hex');
  const encrypted = Buffer.from(parts[1], 'hex');
  const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(key), iv);
  let decrypted = decipher.update(encrypted);
  decrypted = Buffer.concat([decrypted, decipher.final()]);
  return decrypted.toString();
}

const key = crypto.randomBytes(32); // 256 bits
const encrypted = encrypt('Hello World', key);
const decrypted = decrypt(encrypted, key);
console.log(decrypted); // Hello World

工作流模式

使用 Express 构建 REST API 服务
const express = require('express');
const app = express();

// Middleware
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// Logging middleware
app.use((req, res, next) => {
  console.log(`${req.method} ${req.url}`);
  next();
});

// Routes
app.get('/api/users', async (req, res) => {
  try {
    const users = await db.getUsers();
    res.json(users);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

app.get('/api/users/:id', async (req, res) => {
  try {
    const user = await db.getUserById(req.params.id);
    if (!user) {
      return res.status(404).json({ error: 'User not found' });
    }
    res.json(user);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

app.post('/api/users', async (req, res) => {
  try {
    const user = await db.createUser(req.body);
    res.status(201).json(user);
  } catch (err) {
    res.status(400).json({ error: err.message });
  }
});

app.put('/api/users/:id', async (req, res) => {
  try {
    const user = await db.updateUser(req.params.id, req.body);
    if (!user) {
      return res.status(404).json({ error: 'User not found' });
    }
    res.json(user);
  } catch (err) {
    res.status(400).json({ error: err.message });
  }
});

app.delete('/api/users/:id', async (req, res) => {
  try {
    await db.deleteUser(req.params.id);
    res.status(204).end();
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// Error handling middleware
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({ error: 'Internal server error' });
});

// Start server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});
数据库集成
// MongoDB with Mongoose
const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost/myapp', {
  useNewUrlParser: true,
  useUnifiedTopology: true
});

const userSchema = new mongoose.Schema({
  name: { type: String, required: true },
  email: { type: String, required: true, unique: true },
  age: Number,
  createdAt: { type: Date, default: Date.now }
});

const User = mongoose.model('User', userSchema);

// CRUD operations
async function createUser(data) {
  const user = new User(data);
  await user.save();
  return user;
}

async function getUsers() {
  return await User.find();
}

async function getUserById(id) {
  return await User.findById(id);
}

async function updateUser(id, data) {
  return await User.findByIdAndUpdate(id, data, { new: true });
}

async function deleteUser(id) {
  return await User.findByIdAndDelete(id);
}

// PostgreSQL with pg
const { Pool } = require('pg');

const pool = new Pool({
  user: 'dbuser',
  host: 'localhost',
  database: 'mydb',
  password: 'password',
  port: 5432
});

async function queryUsers() {
  const result = await pool.query('SELECT * FROM users');
  return result.rows;
}

async function createUser(name, email) {
  const result = await pool.query(
    'INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *',
    [name, email]
  );
  return result.rows[0];
}
身份验证和授权
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');

// Hash password
async function hashPassword(password) {
  const salt = await bcrypt.genSalt(10);
  return await bcrypt.hash(password, salt);
}

// Verify password
async function verifyPassword(password, hash) {
  return await bcrypt.compare(password, hash);
}

// Generate JWT
function generateToken(user) {
  return jwt.sign(
    { id: user.id, email: user.email },
    process.env.JWT_SECRET,
    { expiresIn: '7d' }
  );
}

// Verify JWT
function verifyToken(token) {
  try {
    return jwt.verify(token, process.env.JWT_SECRET);
  } catch (err) {
    return null;
  }
}

// Auth middleware
function authMiddleware(req, res, next) {
  const token = req.headers.authorization?.split(' ')[1];

  if (!token) {
    return res.status(401).json({ error: 'No token provided' });
  }

  const decoded = verifyToken(token);
  if (!decoded) {
    return res.status(401).json({ error: 'Invalid token' });
  }

  req.user = decoded;
  next();
}

// Login route
app.post('/api/login', async (req, res) => {
  const { email, password } = req.body;

  const user = await User.findOne({ email });
  if (!user) {
    return res.status(401).json({ error: 'Invalid credentials' });
  }

  const isValid = await verifyPassword(password, user.password);
  if (!isValid) {
    return res.status(401).json({ error: 'Invalid credentials' });
  }

  const token = generateToken(user);
  res.json({ token, user: { id: user.id, email: user.email } });
});

// Protected route
app.get('/api/profile', authMiddleware, (req, res) => {
  res.json({ user: req.user });
});

最佳实践

错误处理
// Async error handling wrapper
function asyncHandler(fn) {
  return (req, res, next) => {
    Promise.resolve(fn(req, res, next)).catch(next);
  };
}

// Usage
app.get('/api/users', asyncHandler(async (req, res) => {
  const users = await db.getUsers();
  res.json(users);
}));

// Custom error classes
class AppError extends Error {
  constructor(message, statusCode) {
    super(message);
    this.statusCode = statusCode;
    this.isOperational = true;
    Error.captureStackTrace(this, this.constructor);
  }
}

class NotFoundError extends AppError {
  constructor(message = 'Resource not found') {
    super(message, 404);
  }
}

class ValidationError extends AppError {
  constructor(message = 'Validation failed') {
    super(message, 400);
  }
}

// Global error handler
app.use((err, req, res, next) => {
  const statusCode = err.statusCode || 500;
  const message = err.isOperational ? err.message : 'Internal server error';

  // Log error
  console.error(err);

  // Send response
  res.status(statusCode).json({
    error: message,
    ...(process.env.NODE_ENV === 'development' && { stack: err.stack })
  });
});

// Unhandled errors
process.on('uncaughtException', (err) => {
  console.error('UNCAUGHT EXCEPTION!', err);
  process.exit(1);
});

process.on('unhandledRejection', (err) => {
  console.error('UNHANDLED REJECTION!', err);
  process.exit(1);
});
安全性
// Use helmet for security headers
const helmet = require('helmet');
app.use(helmet());

// Rate limiting
const rateLimit = require('express-rate-limit');

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100 // limit each IP to 100 requests per windowMs
});

app.use('/api/', limiter);

// CORS
const cors = require('cors');

app.use(cors({
  origin: 'https://example.com',
  credentials: true
}));

// Input validation
const { body, validationResult } = require('express-validator');

app.post('/api/users',
  body('email').isEmail().normalizeEmail(),
  body('password').isLength({ min: 8 }),
  body('name').trim().notEmpty(),
  (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({ errors: errors.array() });
    }
    // Process request
  }
);

// Sanitize user input
function sanitize(input) {
  if (typeof input === 'string') {
    return input.replace(/[<>]/g, '');
  }
  return input;
}

// Environment variables
// Never commit .env files
// Use dotenv for local development
require('dotenv').config();

// Secrets management
const secrets = {
  jwtSecret: process.env.JWT_SECRET,
  dbPassword: process.env.DB_PASSWORD,
  apiKey: process.env.API_KEY
};

// Validate required env vars
const requiredEnvVars = ['JWT_SECRET', 'DB_PASSWORD'];
for (const envVar of requiredEnvVars) {
  if (!process.env[envVar]) {
    throw new Error(`Missing required environment variable: ${envVar}`);
  }
}
性能
// Use compression
const compression = require('compression');
app.use(compression());

// Caching
const NodeCache = require('node-cache');
const cache = new NodeCache({ stdTTL: 600 }); // 10 minutes

app.get('/api/data', async (req, res) => {
  const cachedData = cache.get('data');
  if (cachedData) {
    return res.json(cachedData);
  }

  const data = await fetchData();
  cache.set('data', data);
  res.json(data);
});

// Database connection pooling
const pool = new Pool({
  max: 20, // Maximum number of connections
  idleTimeoutMillis: 30000,
  connectionTimeoutMillis: 2000
});

// Use indexes in databases
// MongoDB
userSchema.index({ email: 1 });

// PostgreSQL
// CREATE INDEX idx_users_email ON users(email);

// Pagination
app.get('/api/users', async (req, res) => {
  const page = parseInt(req.query.page) || 1;
  const limit = parseInt(req.query.limit) || 10;
  const skip = (page - 1) * limit;

  const users = await User.find()
    .skip(skip)
    .limit(limit);

  const total = await User.countDocuments();

  res.json({
    data: users,
    page,
    limit,
    total,
    pages: Math.ceil(total / limit)
  });
});

// Optimize queries
// Bad - N+1 query problem
const users = await User.find();
for (const user of users) {
  user.posts = await Post.find({ userId: user.id });
}

// Good - use joins/population
const users = await User.find().populate('posts');

// Stream large responses
app.get('/api/export', (req, res) => {
  res.setHeader('Content-Type', 'application/json');
  res.write('[');

  let first = true;
  User.find().cursor().on('data', (user) => {
    if (!first) res.write(',');
    res.write(JSON.stringify(user));
    first = false;
  }).on('end', () => {
    res.write(']');
    res.end();
  });
});
测试
// Using Jest
const request = require('supertest');
const app = require('./app');

describe('GET /api/users', () => {
  it('should return all users', async () => {
    const res = await request(app)
      .get('/api/users')
      .expect(200);

    expect(Array.isArray(res.body)).toBe(true);
  });
});

describe('POST /api/users', () => {
  it('should create a new user', async () => {
    const userData = {
      name: 'John Doe',
      email: '[email protected]'
    };

    const res = await request(app)
      .post('/api/users')
      .send(userData)
      .expect(201);

    expect(res.body.name).toBe(userData.name);
    expect(res.body.email).toBe(userData.email);
  });

  it('should return 400 for invalid data', async () => {
    const res = await request(app)
      .post('/api/users')
      .send({})
      .expect(400);
  });
});

// Mocking
jest.mock('./database');
const db = require('./database');

test('getUser returns user data', async () => {
  db.getUserById.mockResolvedValue({
    id: 1,
    name: 'John Doe'
  });

  const user = await getUser(1);
  expect(user.name).toBe('John Doe');
});

// Integration tests with test database
beforeAll(async () => {
  await mongoose.connect(process.env.TEST_DB_URL);
});

afterAll(async () => {
  await mongoose.connection.close();
});

beforeEach(async () => {
  await User.deleteMany({});
});
日志记录
// Using winston
const winston = require('winston');

const logger = winston.createLogger({
  level: 'info',
  format: 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('Server started');
logger.error('Error occurred', { error: err.message });

// Request logging
const morgan = require('morgan');
app.use(morgan('combined', {
  stream: {
    write: (message) => logger.info(message.trim())
  }
}));
部署
// Graceful shutdown
const server = app.listen(PORT);

process.on('SIGTERM', () => {
  console.log('SIGTERM received, closing server gracefully');

  server.close(() => {
    console.log('Server closed');

    // Close database connections
    mongoose.connection.close(false, () => {
      console.log('MongoDB connection closed');
      process.exit(0);
    });
  });

  // Force shutdown after 30 seconds
  setTimeout(() => {
    console.error('Forced shutdown');
    process.exit(1);
  }, 30000);
});

// Health check endpoint
app.get('/health', (req, res) => {
  res.json({ status: 'ok', timestamp: Date.now() });
});

// Process monitoring
const v8 = require('v8');
const os = require('os');

app.get('/metrics', (req, res) => {
  const heapStats = v8.getHeapStatistics();

  res.json({
    memory: {
      used: process.memoryUsage().heapUsed,
      total: heapStats.total_heap_size,
      limit: heapStats.heap_size_limit
    },
    cpu: process.cpuUsage(),
    uptime: process.uptime(),
    system: {
      freemem: os.freemem(),
      totalmem: os.totalmem(),
      loadavg: os.loadavg()
    }
  });
});

总结

此 Node.js 开发技能涵盖:

  1. 核心概念:事件循环、模块(CommonJS/ES)、异步模式、流、文件系统、HTTP/HTTPS
  2. API 参考:Buffer、Events、Crypto 和核心模块
  3. 工作流模式:REST API、数据库集成、身份验证
  4. 最佳实践:错误处理、安全性、性能、测试、日志记录、部署
  5. 真实场景示例:用于构建可用于生产环境的应用的完整模式

这些模式和示例体现了现代 Node.js 开发实践,可用于构建可扩展、安全且易于维护的后端应用。

评论

支持 Markdown