当前位置:首页 > 技术 > 正文内容

Node.js开发指南:内置模块、HTTP服务与Nodemon工具

访客 技术 2026年8月13日 3

Node.js作为一款基于Chrome V8引擎的JavaScript运行时,广泛应用于服务器端开发。本文将深入探讨Node.js的核心特性,包括模块化机制、命令行操作、常用的内置模块,以及如何利用Express框架构建Web服务,并介绍强大的开发辅助工具Nodemon。

1. Node.js的模块系统

Node.js默认采用CommonJS规范实现模块化。在这种规范下,每个JavaScript文件都被视为一个独立的模块。模块之间通过特定的语法进行导入和导出。

导出模块内容:

可以使用module.exportsexports对象来暴露模块的接口。module.exports通常用于导出一个默认对象或类,而exports则用于导出多个命名成员。

// utils/mathOperations.js
const add = (a, b) => a + b;
const subtract = (a, b) => a - b;

// 方式一:通过 module.exports 导出一个对象
// module.exports = {
//   addFunction: add,
//   subtractFunction: subtract
// };

// 方式二:通过 exports 导出多个命名成员
exports.add = add;
exports.subtract = subtract;
exports.multiply = (a, b) => a * b;

导入模块:

使用require()函数可以加载并使用其他模块导出的功能。文件路径通常是相对路径,且.js扩展名可以省略。

// main.js
const math = require('./utils/mathOperations'); // .js 后缀可省略

console.log('2 + 3 =', math.add(2, 3));        // 输出: 2 + 3 = 5
console.log('5 - 1 =', math.subtract(5, 1));   // 输出: 5 - 1 = 4
console.log('4 * 6 =', math.multiply(4, 6));   // 输出: 4 * 6 = 24

// 对比ES6模块化语法:
// import { add, subtract } from './utils/mathOperations.js';
// console.log(add(2, 3));

2. 执行JavaScript文件与常用命令行指令

要在Node.js环境中执行JavaScript文件,只需在终端中使用node命令后跟文件名。例如:node app.js

常用的命令行操作:

  • cd [目录路径]:切换当前工作目录。使用Tab键可自动补全路径。
  • cd ..:返回上一级目录。
  • [盘符]::在Windows系统中切换磁盘(如D:)。
  • lsdir:列出当前目录下的文件和子目录。
  • mkdir [目录名]:创建新目录。
  • rmdir [目录名]:删除空目录。
  • clsclear:清空终端屏幕。
  • ipconfig (Windows) / ifconfig (Linux/macOS):显示网络配置信息,包括IP地址。
  • systeminfo (Windows) / uname -a (Linux/macOS):查看操作系统详细信息。

3. Node.js内置核心模块

Node.js提供了一系列强大的内置模块,无需安装即可直接使用,它们提供了操作系统、文件系统、网络通信等底层功能。

3.1 文件系统模块 (fs)

fs模块提供了与文件和目录交互的丰富API。

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

// 异步读取文件内容
fs.readFile(path.join(__dirname, 'config.txt'), 'utf8', (err, data) => {
  if (err) {
    console.error('读取文件失败:', err.message);
    return;
  }
  console.log('文件内容 (异步):', data);
});

// 同步读取文件内容
try {
  const syncData = fs.readFileSync(path.join(__dirname, 'config.txt'), 'utf8');
  console.log('文件内容 (同步):', syncData);
} catch (error) {
  console.error('同步读取文件失败:', error.message);
}

// 异步写入文件内容 (如果文件不存在则创建,存在则覆盖)
fs.writeFile('log.txt', '这是一条日志信息\n', { encoding: 'utf8', flag: 'a' }, (err) => { // flag: 'a' 表示追加
  if (err) {
    console.error('写入文件失败:', err.message);
    return;
  }
  console.log('日志写入成功!');
});

// 检查文件或目录是否存在
const filePath = 'log.txt';
if (fs.existsSync(filePath)) {
  console.log(`${filePath} 存在.`);
} else {
  console.log(`${filePath} 不存在.`);
}

// 获取文件/目录信息 (异步)
fs.stat(filePath, (err, stats) => {
  if (err) {
    console.error('获取文件信息失败:', err.message);
    return;
  }
  console.log(`${filePath} 是文件吗?`, stats.isFile());
  console.log(`${filePath} 是目录吗?`, stats.isDirectory());
  console.log(`${filePath} 大小 (字节):`, stats.size);
});

// 删除文件 (异步)
// fs.unlink('temp.txt', (err) => {
//   if (err) console.error('删除文件失败:', err.message);
//   else console.log('temp.txt 已删除.');
// });

3.2 路径处理模块 (path)

path模块用于处理文件和目录路径,兼容不同操作系统的路径分隔符。

const path = require('path');

// 路径拼接:将多个路径段合并成一个规范化的路径
console.log('路径合并:', path.join('/users', 'john', 'documents', 'report.pdf')); // 输出: /users/john/documents/report.pdf

// 解析为绝对路径:将一系列路径段或相对路径解析为绝对路径
console.log('解析绝对路径:', path.resolve('data', '../config', 'app.json')); // 输出: /your/current/working/dir/config/app.json (根据当前工作目录变化)

// __filename: 当前模块文件的绝对路径
console.log('当前文件路径:', __filename);

// __dirname: 当前模块文件所在目录的绝对路径
console.log('当前目录路径:', __dirname);

// 获取路径中的文件名
console.log('文件名:', path.basename('/home/user/app/index.js')); // 输出: index.js
console.log('文件名 (无扩展名):', path.basename('/home/user/app/index.js', '.js')); // 输出: index

// 获取路径中的目录名
console.log('目录名:', path.dirname('/home/user/app/index.js')); // 输出: /home/user/app

// 获取路径中的文件扩展名
console.log('扩展名:', path.extname('document.docx')); // 输出: .docx
console.log('扩展名:', path.extname('archive.tar.gz')); // 输出: .gz

3.3 操作系统信息模块 (os)

os模块提供了一系列与操作系统相关的方法和属性。

const os = require('os');

console.log('操作系统类型:', os.type()); // 例如: 'Linux', 'Darwin' (macOS), 'Windows_NT'
console.log('操作系统平台:', os.platform()); // 例如: 'linux', 'darwin', 'win32'
console.log('CPU信息:', os.cpus().length, '核');
console.log('总内存 (MB):', (os.totalmem() / 1024 / 1024).toFixed(2));
console.log('空闲内存 (MB):', (os.freemem() / 1024 / 1024).toFixed(2));
console.log('主机名:', os.hostname());
console.log('默认换行符:', JSON.stringify(os.EOL)); // 在Windows上是"\r\n",在Linux/macOS上是"\n"

3.4 URL解析模块 (url)

url模块用于解析和格式化URL字符串。

const url = require('url');

const myUrl = 'http://user:pass@host.com:8080/p/a/t/h?query=string#hash';
const parsedUrl = url.parse(myUrl, true); // true表示解析query字符串为对象

console.log('协议:', parsedUrl.protocol);    // http:
console.log('主机名:', parsedUrl.hostname);  // host.com
console.log('端口:', parsedUrl.port);        // 8080
console.log('路径:', parsedUrl.pathname);    // /p/a/t/h
console.log('查询参数:', parsedUrl.query);   // { query: 'string' }
console.log('哈希:', parsedUrl.hash);        // #hash

3.5 查询字符串模块 (querystring)

querystring模块用于解析和格式化URL查询字符串,类似于HTTP GET请求中的参数部分。

const querystring = require('querystring');

// 将查询字符串解析为对象
const queryStr = 'name=Alice&age=30&city=New%20York';
const parsedObj = querystring.parse(queryStr);
console.log('解析后的对象:', parsedObj); // { name: 'Alice', age: '30', city: 'New York' }

// 将对象格式化为查询字符串
const objToFormat = { product: 'laptop', price: '1200', inStock: 'true' };
const formattedStr = querystring.stringify(objToFormat);
console.log('格式化后的字符串:', formattedStr); // product=laptop&price=1200&inStock=true

// querystring.decode 和 querystring.encode 分别是 querystring.parse 和 querystring.stringify 的别名

3.6 HTTP模块 (http)

http模块是Node.js构建Web服务器的核心,允许创建HTTP服务器和客户端。

创建基本HTTP服务器

// server.js
const http = require('http');

const webServer = http.createServer((request, response) => {
  // request 对象包含客户端请求的所有信息
  // response 对象用于向客户端发送响应

  console.log(`收到来自 ${request.socket.remoteAddress} 的请求: ${request.method} ${request.url}`);

  // 设置响应头,解决中文乱码问题
  response.setHeader('Content-Type', 'text/html; charset=utf-8');

  // 根据请求URL返回不同内容
  if (request.url === '/') {
    response.statusCode = 200; // 设置状态码为200 (OK)
    response.end('<h1>欢迎访问我的Node.js服务器!</h1><p>这是主页内容。</p>');
  } else if (request.url === '/about') {
    response.statusCode = 200;
    response.end('<h2>关于我们</h2><p>Node.js是一款强大的运行时。</p>');
  } else {
    response.statusCode = 404; // 设置状态码为404 (Not Found)
    response.end('<h1>404 Not Found</h1><p>您请求的页面不存在。</p>');
  }
});

const PORT = 3000;
webServer.listen(PORT, () => {
  console.log(`HTTP服务器已启动,监听端口 ${PORT}`);
  console.log(`请访问: http://localhost:${PORT}`);
});

提供静态资源服务

以下示例展示如何搭建一个简单的静态文件服务器,将public目录下的文件作为静态资源提供。

// staticServer.js
const http = require('http');
const path = require('path');
const fs = require('fs');

// 定义静态文件目录
const STATIC_DIR = path.join(__dirname, 'public');

const staticWebServer = http.createServer((req, res) => {
  let requestPath = req.url;

  // 处理根路径请求,默认返回 index.html
  if (requestPath === '/') {
    requestPath = '/index.html';
  }

  // 忽略 favicon.ico 请求,或者提供一个真实的 favicon
  if (requestPath === '/favicon.ico') {
    res.statusCode = 204; // No Content
    res.end();
    return;
  }

  const filePath = path.join(STATIC_DIR, requestPath);

  // 检查文件是否存在
  fs.access(filePath, fs.constants.F_OK, (err) => {
    if (err) {
      // 文件不存在
      res.setHeader('Content-Type', 'text/html; charset=utf-8');
      res.statusCode = 404;
      res.end('<h1>404 资源未找到</h1><p>您请求的文件或页面不存在。</p>');
      return;
    }

    // 文件存在,读取并返回
    fs.readFile(filePath, (readErr, data) => {
      if (readErr) {
        // 读取文件失败
        console.error(`读取文件失败: ${readErr.message}`);
        res.setHeader('Content-Type', 'text/html; charset=utf-8');
        res.statusCode = 500;
        res.end('<h1>500 服务器内部错误</h1><p>无法提供请求的资源。</p>');
        return;
      }
      // 根据文件扩展名设置MIME类型
      const ext = path.extname(filePath);
      let contentType = 'application/octet-stream';
      switch (ext) {
        case '.html': contentType = 'text/html'; break;
        case '.css': contentType = 'text/css'; break;
        case '.js': contentType = 'application/javascript'; break;
        case '.json': contentType = 'application/json'; break;
        case '.png': contentType = 'image/png'; break;
        case '.jpg':
        case '.jpeg': contentType = 'image/jpeg'; break;
        // 更多类型...
      }
      res.setHeader('Content-Type', `${contentType}; charset=utf-8`);
      res.statusCode = 200;
      res.end(data);
    });
  });
});

const STATIC_PORT = 8080;
staticWebServer.listen(STATIC_PORT, () => {
  console.log(`静态文件服务器在 http://localhost:${STATIC_PORT} 运行`);
});

在项目根目录创建一个public文件夹,并在其中放置index.htmlstyle.css等文件进行测试。

处理GET请求参数

const http = require('http');
const url = require('url');

http.createServer((req, res) => {
  res.setHeader('Content-Type', 'application/json; charset=utf-8');
  const { pathname, query } = url.parse(req.url, true); // true 将查询字符串解析为对象

  if (pathname === '/api/data') {
    res.statusCode = 200;
    res.end(JSON.stringify({
      message: '接收到GET请求数据',
      parameters: query
    }));
  } else {
    res.statusCode = 404;
    res.end(JSON.stringify({ error: '路径不存在' }));
  }
}).listen(3001, () => console.log('GET API Server running on http://localhost:3001'));

处理POST请求体数据

POST请求的数据可能分批发送,需要监听data事件来收集数据块,并在end事件触发时将它们拼接起来。

const http = require('http');
const querystring = require('querystring');

http.createServer((req, res) => {
  if (req.method === 'POST' && req.url === '/api/submit') {
    let requestBodyChunks = [];
    req.on('data', (chunk) => {
      requestBodyChunks.push(chunk);
    });

    req.on('end', () => {
      const fullRequestBody = Buffer.concat(requestBodyChunks).toString();
      const contentType = req.headers['content-type'] || '';

      let parsedData = {};
      if (contentType.includes('application/x-www-form-urlencoded')) {
        parsedData = querystring.parse(fullRequestBody);
      } else if (contentType.includes('application/json')) {
        try {
          parsedData = JSON.parse(fullRequestBody);
        } catch (e) {
          res.statusCode = 400;
          res.end(JSON.stringify({ error: '无效的JSON数据' }));
          return;
        }
      }

      res.setHeader('Content-Type', 'application/json; charset=utf-8');
      res.statusCode = 200;
      res.end(JSON.stringify({
        message: '成功接收POST请求数据',
        receivedData: parsedData
      }));
    });
  } else {
    res.setHeader('Content-Type', 'application/json; charset=utf-8');
    res.statusCode = 405;
    res.end(JSON.stringify({ error: '不支持的请求方法或路径' }));
  }
}).listen(3002, () => console.log('POST API Server running on http://localhost:3002'));

HTTP代理示例

使用http-proxy-middleware可以方便地创建HTTP代理,常用于解决开发环境的跨域问题。

const http = require('http');
// 首先需要安装:npm install http-proxy-middleware
const { createProxyMiddleware } = require('http-proxy-middleware');

// 示例代理配置
const proxyConfig = createProxyMiddleware('/api', {
  target: 'https://jsonplaceholder.typicode.com', // 目标API服务地址
  changeOrigin: true, // 改变请求头中的Host字段,使其与目标URL的主机名相同
  pathRewrite: {
    '^/api': '', // 将请求路径中的 /api 替换为空,例如 /api/users 会被代理到 /users
  },
  onProxyReq: (proxyReq, req, res) => {
    // 可以在代理请求发送前修改请求
    console.log(`代理请求到: ${proxyReq.path}`);
  },
  onError: (err, req, res) => {
    res.writeHead(500, {
      'Content-Type': 'text/plain',
    });
    res.end('代理请求失败: ' + err.message);
  }
});

const proxyServer = http.createServer((req, res) => {
  // 只有请求路径匹配 /api 才会被代理
  if (req.url.startsWith('/api')) {
    proxyConfig(req, res); // 调用代理中间件
  } else {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('欢迎访问我的主页,尝试访问 /api/posts');
  }
});

proxyServer.listen(3003, () => {
  console.log('代理服务器运行在 http://localhost:3003');
  console.log('访问 http://localhost:3003/api/posts 即可代理到 https://jsonplaceholder.typicode.com/posts');
});

4. Express.js框架入门

Express是Node.js平台上一个快速、开放、极简的Web开发框架。它简化了Web服务器和API接口的构建过程。

安装依赖:

npm install express
npm install art-template express-art-template # 如需使用模板引擎

基本Express应用与模板引擎

以下示例展示如何使用Express创建一个简单的Web服务器,并结合art-template渲染动态页面。

// expressApp.js
const express = require('express');
const path = require('path');

// 创建Express应用实例
const app = express();

// 配置静态资源目录
// 任何以 /static 开头的请求都会去 'public' 目录下查找文件
// 例如:访问 http://localhost:4000/static/style.css 会读取 public/style.css
app.use('/static', express.static(path.join(__dirname, 'public')));

// 配置模板引擎 (以 .html 结尾的文件使用 art-template 渲染)
app.engine('html', require('express-art-template'));
// 设置模板文件存放目录
app.set('views', path.join(__dirname, 'views'));
// 设置模板引擎的默认后缀 (可选,如果文件名带有后缀可不设置)
app.set('view engine', 'html');

// 定义根路由,渲染 'index.html' 模板
app.get('/', (req, res) => {
  const pageData = {
    title: 'Express应用首页',
    features: ['快速开发', '强大的路由', '中间件支持'],
    isLoggedIn: true
  };
  // 渲染 views/index.html 模板,并传入数据
  res.render('index', pageData);
});

// 定义一个简单的API路由
app.get('/api/greeting', (req, res) => {
  const name = req.query.name || '访客';
  res.json({ message: `你好,${name}!` }); // 发送JSON响应
});

// 监听指定端口
const EXPRESS_PORT = 4000;
app.listen(EXPRESS_PORT, () => {
  console.log(`Express应用运行在 http://localhost:${EXPRESS_PORT}`);
});

在项目根目录创建public文件夹(存放CSS/JS等静态文件)和views文件夹(存放HTML模板文件)。

views/index.html示例:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>{{ title }}</title>
    <link rel="stylesheet" href="/static/style.css">
</head>
<body>
    <h1>{{ title }}</h1>
    <p>当前用户:{{ isLoggedIn ? '已登录' : '未登录' }}</p>
    <h2>主要特性:</h2>
    <ul>
        {{ each features }}
            <li>{{ $value }}</li>
        {{ /each }}
    </ul>
    <script src="/static/app.js"></script>
</body>
</html>

Express路由基础

Express的核心是其强大的路由系统,允许根据HTTP方法和URL路径定义不同的请求处理逻辑。

// expressRouter.js
const express = require('express');
const app = express();

// 中间件:用于解析JSON格式的请求体
app.use(express.json());
// 中间件:用于解析URL-encoded格式的请求体 (例如HTML表单提交)
app.use(express.urlencoded({ extended: true }));

// GET请求示例
app.get('/users/:id', (req, res) => {
  const userId = req.params.id; // 获取URL参数
  const queryParam = req.query.sort; // 获取查询字符串参数
  res.status(200).send(`查询用户 ID: ${userId}, 排序方式: ${queryParam || '默认'}`);
});

// POST请求示例
app.post('/products', (req, res) => {
  const productData = req.body; // 获取请求体数据
  if (!productData || !productData.name || !productData.price) {
    return res.status(400).json({ error: '产品名称和价格是必填项' });
  }
  console.log('接收到新产品数据:', productData);
  res.status(201).json({ message: '产品创建成功', data: productData });
});

// PUT请求示例
app.put('/items/:itemId', (req, res) => {
  const itemId = req.params.itemId;
  const updateData = req.body;
  res.status(200).json({ message: `项目 ${itemId} 已更新`, new_data: updateData });
});

// DELETE请求示例
app.delete('/data/:recordId', (req, res) => {
  const recordId = req.params.recordId;
  res.status(204).send(`记录 ${recordId} 已删除`); // 204 No Content
});

app.listen(4001, () => {
  console.log('Express路由服务器运行在 http://localhost:4001');
});

5. Nodemon开发辅助工具

nodemon是一个非常实用的命令行工具,它会监听Node.js项目中的文件变动。一旦检测到文件更改,nodemon会自动重启Node.js应用程序,极大地提高了开发效率,避免了手动停止和重启服务器的繁琐操作。

安装 Nodemon:

nodemon通常作为全局工具安装,以便在任何项目中使用。

npm install --global nodemon
# 或者使用 yarn
yarn global add nodemon

验证安装:

nodemon --version

使用 Nodemon 运行文件:

安装后,可以使用nodemon命令替代node命令来启动您的JavaScript文件。

nodemon your-app.js

现在,当your-app.js文件或其依赖的文件发生修改并保存时,Node.js应用程序将自动重新启动。

卸载 Nodemon (如果不再需要):

npm uninstall --global nodemon
# 或者使用 yarn
yarn global remove nodemon

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

linux screen 用法详情 (nohup 的替代方案)

一、screen 是什么?能干嘛?screen 是一个终端复用器,可以:在一个 SSH 会话中开多个“虚拟终端”SSH 断线后,程序仍然在后台运行随时重新连接到原来的会话特别适合:nohup 的替代方案跑脚本 / 爬虫 / 训练模型运维、远程开发二、安装 screen# CentOS / Rocky / Almayum install -y screen# Debian / Ubuntuapt i...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。