【node.js】入门基础

发布于:2025-05-21 ⋅ 阅读:(16) ⋅ 点赞:(0)

在这里插入图片描述

个人主页:Guiat
归属专栏:node.js

在这里插入图片描述

正文

1. Node.js简介

Node.js是一个开源、跨平台的JavaScript运行环境,它允许开发者使用JavaScript来编写服务器端代码。Node.js采用Google Chrome的V8引擎来执行JavaScript代码,具有非阻塞I/O和事件驱动机制,使其成为构建高性能网络应用的理想选择。

1.1 Node.js的核心特点

Node.js核心特点
非阻塞I/O
事件驱动
单线程
跨平台
npm生态系统
  • 非阻塞I/O:执行I/O操作时不会阻塞线程
  • 事件驱动:基于事件循环处理并发操作
  • 单线程:使用单线程处理多个并发连接
  • 跨平台:可在Windows、macOS和Linux等多种操作系统上运行
  • npm:拥有世界上最大的开源代码库生态系统

1.2 Node.js适用场景

Node.js特别适合以下场景:

  • 实时应用(聊天、游戏服务器)
  • REST API和微服务
  • 单页面应用(SPA)的后端
  • 流处理和数据密集型应用
  • 命令行工具

2. 第一个Node.js程序

2.1 创建并运行Hello World

创建一个名为hello.js的文件,内容如下:

// 第一个Node.js程序
console.log("Hello, Node.js!");

在命令行中运行:

node hello.js

输出结果:

Hello, Node.js!

2.2 创建简单的HTTP服务器

创建一个基本的Web服务器:

// 创建简单的HTTP服务器
const http = require('http');

// 创建HTTP服务器
const server = http.createServer((req, res) => {
  // 设置响应头
  res.writeHead(200, {'Content-Type': 'text/plain'});
  
  // 发送响应数据
  res.end('Hello World from Node.js Server!');
});

// 服务器监听3000端口
const PORT = 3000;
server.listen(PORT, () => {
  console.log(`Server running at http://localhost:${PORT}/`);
});

运行服务器:

node server.js

现在可以在浏览器中访问http://localhost:3000查看结果。

3. Node.js核心概念

3.1 模块系统

Node.js使用CommonJS模块系统,允许将代码分割成可重用的部分。

3.1.1 创建和导出模块

// math.js - 创建一个数学工具模块
function add(a, b) {
  return a + b;
}

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

function multiply(a, b) {
  return a * b;
}

function divide(a, b) {
  if (b === 0) {
    throw new Error('Cannot divide by zero');
  }
  return a / b;
}

// 导出多个函数
module.exports = {
  add,
  subtract,
  multiply,
  divide
};

3.1.2 导入和使用模块

// app.js - 使用数学工具模块
const math = require('./math');

console.log(`2 + 3 = ${math.add(2, 3)}`);
console.log(`5 - 2 = ${math.subtract(5, 2)}`);
console.log(`4 * 6 = ${math.multiply(4, 6)}`);
console.log(`10 / 2 = ${math.divide(10, 2)}`);

// 也可以使用解构赋值
const { add, multiply } = require('./math');
console.log(`4 + 5 = ${add(4, 5)}`);
console.log(`3 * 7 = ${multiply(3, 7)}`);

3.1.3 ES模块语法(ES Modules)

Node.js也支持ES模块语法,需要将文件后缀改为.mjs或在package.json中设置"type": "module"

// mathES.mjs - ES模块语法
export function add(a, b) {
  return a + b;
}

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

// 导出默认值
export default {
  name: 'Math Utils',
  version: '1.0.0'
};
// appES.mjs - 导入ES模块
import { add, subtract } from './mathES.mjs';
import mathInfo from './mathES.mjs';

console.log(`ES模块: 2 + 3 = ${add(2, 3)}`);
console.log(`模块信息: ${mathInfo.name} v${mathInfo.version}`);

3.2 事件循环

Node.js的事件循环是其非阻塞I/O模型的核心,它允许Node.js执行非阻塞操作。

事件循环
定时器阶段
待定回调阶段
idle/prepare阶段
轮询阶段
检查阶段
关闭回调阶段

3.2.1 事件循环示例

console.log('1. 开始执行');

// 延迟执行 (宏任务)
setTimeout(() => {
  console.log('4. setTimeout 回调执行');
}, 0);

// Promise (微任务)
Promise.resolve().then(() => {
  console.log('3. Promise 回调执行');
});

console.log('2. 结束执行');

// 输出顺序:
// 1. 开始执行
// 2. 结束执行
// 3. Promise 回调执行
// 4. setTimeout 回调执行

3.2.2 异步文件操作示例

const fs = require('fs');

console.log('1. 开始读取文件');

// 异步读取文件
fs.readFile('example.txt', 'utf8', (err, data) => {
  if (err) {
    console.error('读取文件出错:', err);
    return;
  }
  console.log('3. 文件内容:', data);
});

console.log('2. 读取文件的请求已发出,继续执行其他操作');

3.3 事件发射器 (EventEmitter)

EventEmitter是Node.js的核心模块,用于实现事件驱动架构。

const EventEmitter = require('events');

// 创建事件发射器实例
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();

// 注册事件监听器
myEmitter.on('event', (a, b) => {
  console.log('事件发生了!', a, b);
});

// 注册只执行一次的事件监听器
myEmitter.once('onceEvent', () => {
  console.log('这个事件只会触发一次');
});

// 触发事件
myEmitter.emit('event', 'a', 'b');
myEmitter.emit('onceEvent');
myEmitter.emit('onceEvent'); // 这次不会触发监听器

3.3.1 自定义事件发射器

const EventEmitter = require('events');

// 创建一个用户类,继承EventEmitter
class User extends EventEmitter {
  constructor(name) {
    super();
    this.name = name;
  }
  
  sayHello() {
    console.log(`${this.name} says hello!`);
    // 触发事件
    this.emit('hello', this.name);
  }
  
  sayGoodbye() {
    console.log(`${this.name} says goodbye!`);
    // 触发事件
    this.emit('goodbye', this.name);
  }
}

// 创建用户实例
const user = new User('John');

// 添加事件监听器
user.on('hello', (name) => {
  console.log(`Hello event was triggered by ${name}`);
});

user.on('goodbye', (name) => {
  console.log(`Goodbye event was triggered by ${name}`);
});

// 调用方法,触发事件
user.sayHello();
user.sayGoodbye();

3.4 流 (Streams)

流是用于处理读写数据的抽象接口,尤其适合处理大文件。

3.4.1 流的类型

  • 可读流 (Readable):用于读取数据
  • 可写流 (Writable):用于写入数据
  • 双工流 (Duplex):可读可写
  • 转换流 (Transform):在读写过程中修改数据

3.4.2 文件流示例

const fs = require('fs');

// 创建可读流
const readStream = fs.createReadStream('source.txt', 'utf8');

// 创建可写流
const writeStream = fs.createWriteStream('destination.txt');

// 处理流事件
readStream.on('data', (chunk) => {
  console.log(`接收到 ${chunk.length} 字节的数据`);
  // 写入数据到可写流
  writeStream.write(chunk);
});

readStream.on('end', () => {
  writeStream.end(); // 结束写入流
  console.log('读取完成');
});

readStream.on('error', (err) => {
  console.error('读取错误:', err);
});

writeStream.on('finish', () => {
  console.log('写入完成');
});

writeStream.on('error', (err) => {
  console.error('写入错误:', err);
});

3.4.3 使用pipe()简化流操作

const fs = require('fs');

// 创建可读流和可写流
const readStream = fs.createReadStream('source.txt');
const writeStream = fs.createWriteStream('destination.txt');

// 使用pipe直接将可读流连接到可写流
readStream.pipe(writeStream);

// 处理事件
readStream.on('end', () => {
  console.log('读取完成');
});

writeStream.on('finish', () => {
  console.log('写入完成');
});

3.4.4 创建自定义流

const { Transform } = require('stream');

// 创建转换流,将文本转为大写
class UppercaseTransform extends Transform {
  _transform(chunk, encoding, callback) {
    // 转换数据
    const upperChunk = chunk.toString().toUpperCase();
    // 推送转换后的数据
    this.push(upperChunk);
    // 调用回调,表示处理完成
    callback();
  }
}

// 使用自定义转换流
const upperCaseStream = new UppercaseTransform();

// 从标准输入读取,经过转换后写入标准输出
process.stdin
  .pipe(upperCaseStream)
  .pipe(process.stdout);

4. 文件系统操作

Node.js提供了fs模块用于与文件系统交互。

4.1 同步与异步文件操作

const fs = require('fs');

// 同步读取文件(阻塞)
try {
  const data = fs.readFileSync('file.txt', 'utf8');
  console.log('同步读取文件:', data);
} catch (err) {
  console.error('同步读取错误:', err);
}

// 异步读取文件(非阻塞)
fs.readFile('file.txt', 'utf8', (err, data) => {
  if (err) {
    console.error('异步读取错误:', err);
    return;
  }
  console.log('异步读取文件:', data);
});

// 使用Promise API (Node.js 10+)
fs.promises.readFile('file.txt', 'utf8')
  .then(data => {
    console.log('Promise读取文件:', data);
  })
  .catch(err => {
    console.error('Promise读取错误:', err);
  });

// 使用async/await (Node.js 10+)
async function readFileAsync() {
  try {
    const data = await fs.promises.readFile('file.txt', 'utf8');
    console.log('Async/Await读取文件:', data);
  } catch (err) {
    console.error('Async/Await读取错误:', err);
  }
}

readFileAsync();

4.2 写入文件

const fs = require('fs');

// 同步写入
try {
  fs.writeFileSync('output1.txt', 'Hello, Node.js! (同步写入)', 'utf8');
  console.log('同步写入完成');
} catch (err) {
  console.error('同步写入错误:', err);
}

// 异步写入
fs.writeFile('output2.txt', 'Hello, Node.js! (异步写入)', 'utf8', (err) => {
  if (err) {
    console.error('异步写入错误:', err);
    return;
  }
  console.log('异步写入完成');
});

// 追加内容到文件
fs.appendFile('output2.txt', '\n这是追加的内容', 'utf8', (err) => {
  if (err) {
    console.error('追加错误:', err);
    return;
  }
  console.log('追加完成');
});

4.3 目录操作

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

// 创建目录
fs.mkdir('new-directory', (err) => {
  if (err) {
    console.error('创建目录错误:', err);
    return;
  }
  console.log('目录创建成功');
});

// 递归创建多级目录
fs.mkdir('parent/child/grandchild', { recursive: true }, (err) => {
  if (err) {
    console.error('创建多级目录错误:', err);
    return;
  }
  console.log('多级目录创建成功');
});

// 读取目录内容
fs.readdir('.', (err, files) => {
  if (err) {
    console.error('读取目录错误:', err);
    return;
  }
  console.log('当前目录文件:');
  files.forEach(file => {
    console.log(`- ${file}`);
  });
});

// 获取文件信息
fs.stat('file.txt', (err, stats) => {
  if (err) {
    console.error('获取文件信息错误:', err);
    return;
  }
  console.log('文件信息:');
  console.log(`- 是文件? ${stats.isFile()}`);
  console.log(`- 是目录? ${stats.isDirectory()}`);
  console.log(`- 文件大小: ${stats.size} 字节`);
  console.log(`- 创建时间: ${stats.birthtime}`);
  console.log(`- 修改时间: ${stats.mtime}`);
});

4.4 文件路径操作

const path = require('path');

// 路径拼接 (跨平台兼容)
const fullPath = path.join(__dirname, 'subfolder', 'file.txt');
console.log('拼接路径:', fullPath);

// 解析路径
const pathInfo = path.parse('/home/user/documents/file.txt');
console.log('路径信息:', pathInfo);
/*
输出:
{
  root: '/',
  dir: '/home/user/documents',
  base: 'file.txt',
  ext: '.txt',
  name: 'file'
}
*/

// 规范化路径
console.log('规范化路径:', path.normalize('/home//user/../user/docs/'));
// 输出: /home/user/docs/

// 获取绝对路径
console.log('绝对路径:', path.resolve('subfolder', 'file.txt'));

// 获取扩展名
console.log('扩展名:', path.extname('file.txt')); // 输出: .txt

5. HTTP服务器开发

5.1 创建基本HTTP服务器

const http = require('http');

// 创建HTTP服务器
const server = http.createServer((req, res) => {
  // 获取请求信息
  const { method, url, headers } = req;
  console.log(`收到 ${method} 请求: ${url}`);
  
  // 根据URL路径提供不同响应
  if (url === '/') {
    // 设置响应头
    res.writeHead(200, {'Content-Type': 'text/html'});
    // 发送响应数据
    res.end(`
      <html>
        <head><title>Node.js服务器</title></head>
        <body>
          <h1>欢迎来到Node.js服务器!</h1>
          <p>当前时间: ${new Date().toLocaleString()}</p>
          <ul>
            <li><a href="/about">关于我们</a></li>
            <li><a href="/contact">联系我们</a></li>
          </ul>
        </body>
      </html>
    `);
  } 
  else if (url === '/about') {
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.end(`
      <html>
        <head><title>关于我们</title></head>
        <body>
          <h1>关于我们</h1>
          <p>这是一个简单的Node.js HTTP服务器示例。</p>
          <a href="/">返回首页</a>
        </body>
      </html>
    `);
  }
  else if (url === '/contact') {
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.end(`
      <html>
        <head><title>联系我们</title></head>
        <body>
          <h1>联系我们</h1>
          <p>Email: example@example.com</p>
          <a href="/">返回首页</a>
        </body>
      </html>
    `);
  }
  else if (url === '/api/time') {
    // 返回JSON数据
    res.writeHead(200, {'Content-Type': 'application/json'});
    res.end(JSON.stringify({
      time: new Date().toISOString(),
      timestamp: Date.now()
    }));
  }
  else {
    // 404 Not Found
    res.writeHead(404, {'Content-Type': 'text/html'});
    res.end(`
      <html>
        <head><title>404 Not Found</title></head>
        <body>
          <h1>404 - 页面不存在</h1>
          <p>请求的URL "${url}" 不存在</p>
          <a href="/">返回首页</a>
        </body>
      </html>
    `);
  }
});

// 服务器监听端口
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
  console.log(`服务器运行在 http://localhost:${PORT}/`);
});

5.2 处理HTTP请求和路由

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

// 路由处理函数
const routes = {
  'GET': {
    '/': (req, res) => {
      res.writeHead(200, {'Content-Type': 'text/html'});
      res.end('<h1>首页</h1><p>欢迎访问我们的网站</p>');
    },
    '/about': (req, res) => {
      res.writeHead(200, {'Content-Type': 'text/html'});
      res.end('<h1>关于我们</h1><p>这是关于页面</p>');
    },
    '/api/users': (req, res) => {
      const users = [
        { id: 1, name: 'Alice' },
        { id: 2, name: 'Bob' },
        { id: 3, name: 'Charlie' }
      ];
      res.writeHead(200, {'Content-Type': 'application/json'});
      res.end(JSON.stringify(users));
    }
  },
  'POST': {
    '/api/users': (req, res) => {
      let body = '';
      
      // 收集请求体数据
      req.on('data', chunk => {
        body += chunk.toString();
      });
      
      // 请求体接收完毕
      req.on('end', () => {
        try {
          const userData = JSON.parse(body);
          // 处理用户数据...
          res.writeHead(201, {'Content-Type': 'application/json'});
          res.end(JSON.stringify({
            message: '用户创建成功',
            user: userData
          }));
        } catch (error) {
          res.writeHead(400, {'Content-Type': 'application/json'});
          res.end(JSON.stringify({
            error: '无效的JSON数据'
          }));
        }
      });
    }
  }
};

// 创建HTTP服务器
const server = http.createServer((req, res) => {
  // 解析URL和查询参数
  const parsedUrl = url.parse(req.url, true);
  const path = parsedUrl.pathname;
  const method = req.method.toUpperCase();
  const query = parsedUrl.query;
  
  console.log(`${method} ${path}`);
  
  // 查找路由处理函数
  const routeHandler = routes[method] && routes[method][path];
  
  if (routeHandler) {
    // 将查询参数附加到请求对象
    req.query = query;
    // 调用路由处理函数
    routeHandler(req, res);
  } else {
    // 未找到路由处理函数,返回404
    res.writeHead(404, {'Content-Type': 'text/html'});
    res.end('<h1>404 - 页面不存在</h1>');
  }
});

// 启动服务器
const PORT = 3000;
server.listen(PORT, () => {
  console.log(`服务器运行在 http://localhost:${PORT}/`);
});

5.3 处理静态文件

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

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

// MIME类型映射
const MIME_TYPES = {
  '.html': 'text/html',
  '.css': 'text/css',
  '.js': 'text/javascript',
  '.json': 'application/json',
  '.png': 'image/png',
  '.jpg': 'image/jpeg',
  '.jpeg': 'image/jpeg',
  '.gif': 'image/gif',
  '.svg': 'image/svg+xml',
  '.ico': 'image/x-icon',
  '.txt': 'text/plain'
};

// 创建HTTP服务器
const server = http.createServer((req, res) => {
  // 仅处理GET请求
  if (req.method !== 'GET') {
    res.writeHead(405, {'Content-Type': 'text/plain'});
    res.end('Method Not Allowed');
    return;
  }
  
  // 获取请求路径
  let filePath = path.join(PUBLIC_DIR, req.url === '/' ? 'index.html' : req.url);
  
  // 检查文件是否存在
  fs.stat(filePath, (err, stats) => {
    if (err) {
      // 文件不存在,返回404
      res.writeHead(404, {'Content-Type': 'text/html'});
      res.end('<h1>404 - 文件未找到</h1>');
      return;
    }
    
    // 如果是目录,尝试加载index.html
    if (stats.isDirectory()) {
      filePath = path.join(filePath, 'index.html');
    }
    
    // 获取文件扩展名
    const extname = path.extname(filePath);
    
    // 获取MIME类型
    const contentType = MIME_TYPES[extname] || 'application/octet-stream';
    
    // 读取并发送文件
    fs.readFile(filePath, (err, content) => {
      if (err) {
        if (err.code === 'ENOENT') {
          // 文件不存在
          res.writeHead(404, {'Content-Type': 'text/html'});
          res.end('<h1>404 - 文件未找到</h1>');
        } else {
          // 服务器错误
          res.writeHead(500, {'Content-Type': 'text/html'});
          res.end('<h1>500 - 服务器错误</h1>');
        }
      } else {
        // 发送文件
        res.writeHead(200, {'Content-Type': contentType});
        res.end(content);
      }
    });
  });
});

// 启动服务器
const PORT = 3000;
server.listen(PORT, () => {
  console.log(`静态文件服务器运行在 http://localhost:${PORT}/`);
  console.log(`提供目录: ${PUBLIC_DIR}`);
});

结语
感谢您的阅读!期待您的一键三连!欢迎指正!

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到