Day 1:Node.js 入门指南——从环境搭建到第一个HTTP服务器

340 阅读7分钟

Day 1:Node.js 入门指南——从环境搭建到第一个HTTP服务器

今日学习目标

  1. 理解 Node.js 的核心概念与特点。
  2. 完成开发环境搭建并运行第一个脚本。
  3. 掌握 Node.js 的模块化开发(require 和 module.exports)。
  4. 用原生 http 模块创建一个简单的 HTTP 服务器。

🌍 Node.js 简介

1. 什么是 Node.js?

Node.js 是一个基于 Chrome V8 引擎 的 JavaScript 运行时,用于构建高性能的服务器端应用。它的核心特点包括:

  • 事件驱动:通过事件循环(Event Loop)处理并发请求。
  • 非阻塞 I/O:异步操作文件、网络等,避免线程阻塞。
  • 单线程但支持多进程:可通过 cluster 模块利用多核 CPU。

2. Node.js 与浏览器 JavaScript 的区别

  • 无 BOM/DOM:Node.js 没有 window 或 document 对象,专注于系统级 API(如文件操作、网络服务)。
  • 模块化系统:使用 CommonJS 规范(require 和 exports),而非浏览器的 ES Modules。

环境搭建

1. 安装 Node.js

  1. 下载 LTS 版本(推荐企业级使用):Node.js 官网
微信图片_2025-06-22_145654_369.png
  1. 下载完成之后双击,一路点击next即可完成安装

  2. 验证安装:

  node -v  # 查看 Node.js 版本
  npm -v   # 查看 npm 版本
  1. 我的版本参考
   node -v
   --v22.16.0
   npm -v
   --10.9.2

2. 编辑器配置

推荐使用 VS Code,安装插件:

  • ESLint(代码规范检查)。
  • REST Client(测试 HTTP 接口)。

1. 第一个 Node.js 脚本

创建 index.js

console.log("这是我的第一个node.js");

运行:

node index.js

✅ 输出

这是我的第一个node.js

VS Code操作截图:

8aeb9e38-767c-40fc-9b1a-c8e1d530181d.png

4. 文件的读写操作

读取文件内容

我的目录结构:

├── a.txt   
└── read.js

Node.js 采用 CommonJS 模块系统:我们需要读取一个文件,这里可以在我们的官方文档:文件操作去查阅相关的API

160f1107-46ee-4368-b4c8-1b69d3177ea7.png 往下翻我们能看到- fsPromises.readFile(path[, options]),点进去是相关的使用案例

微信图片_2025-06-22_153536_987.png 下面是我的代码:

1.方法一:Promise


// 引入Node.js的文件系统Promise版本模块(使用node:协议明确指定核心模块)
// readFile是一个返回Promise的异步文件读取方法
const { readFile } = require('node:fs/promises');

// 引入Node.js的路径处理模块
// resolve方法用于将路径片段解析为绝对路径
const { resolve } = require('node:path');

// 定义异步函数读取并打印文件内容
async function logFile() {
  try {
    // 使用resolve方法将相对路径'./a.txt'解析为绝对路径
    // 这样可以避免路径拼接错误,确保总能找到正确位置的文件
    const filePath = resolve('./a.txt');
    
    // 使用await异步读取文件内容
    // 参数说明:
    // filePath - 要读取的文件路径
    // { encoding: 'utf8' } - 以UTF-8编码读取文件内容,直接返回字符串而不是Buffer
    const contents = await readFile(filePath, { encoding: 'utf8' });
    
    // 打印文件内容,使用模板字符串拼接了文件名和文件内容
    console.log(`${filePath}文件的内容是:${contents}`);
  } catch (err) {
    // 捕获并处理可能出现的错误
    // 例如:文件不存在、权限问题等
    // 这里只打印错误的基本信息,避免暴露过多细节
    console.error(err.message);
  }
}

// 调用异步函数
// 注意:在顶层使用await需要Node.js 14.8.0+或在ES模块中
logFile();

// 补充说明:
// 1. 使用node:fs/promises而不是回调风格的fs模块,代码更简洁

2. 方法二:CallBack

//导入FS模块
// 引入Node.js内置的fs(文件系统)模块
// fs模块提供了文件操作的API
const fs = require('fs')

// 使用fs.readFile()方法异步读取文件内容
// 参数说明:
// 1. './a.txt' - 要读取的文件路径(相对路径)
// 2. 'utf-8' - 指定以UTF-8编码读取文件,返回字符串而不是Buffer
// 3. function(err, data) - 回调函数,Node.js标准的错误优先回调风格
fs.readFile('./a.txt', 'utf-8', function(err, data) {
    // 错误处理
    // 注意:正确语法是if (err),这里缺少括号
    if (err) {
        // 如果读取出错,打印错误信息
        console.error(err)
        // 建议在这里return,避免继续执行后面的代码
        return
    }
    
    // 如果读取成功,打印文件内容
    // 由于指定了'utf-8'编码,data是字符串类型
    console.log(data)
})

运行:`node read.js`
```text
a.txt文件的内容是:hahaha

我们刚刚实现了读操作,那么试一下写操作呢:

1. 方法一:Promise

// 导入Node.js的文件系统Promise API中的writeFile方法
// 使用node:前缀明确指定使用Node.js核心模块
import { writeFile } from 'node:fs/promises';

// 导入Node.js的路径处理模块中的resolve方法
// 用于将相对路径解析为绝对路径
import { resolve } from 'node:path';

// 定义异步函数用于写入文件
async function writeToFile() {
  // 创建AbortController实例,用于控制异步操作的取消
  const controller = new AbortController();
  
  // 从controller中解构出signal对象
  // signal用于传递给异步操作,以便可以取消操作
  const { signal } = controller;
  
  try {
    // 使用resolve方法将相对路径'./a.txt'解析为绝对路径
    // 这样可以确保在不同工作目录下都能找到正确的文件位置
    const filePath = resolve('./a.txt'); 
    
    // 使用await异步写入文件
    // 参数说明:
    // 1. filePath - 要写入的文件路径
    // 2. '写入的值' - 要写入的内容
    // 3. { 
    //      encoding: 'utf-8' - 指定使用UTF-8编码写入文件
    //      signal - 传递AbortSignal以便可以取消操作
    //    }
    await writeFile(filePath, '写入的值', { 
      encoding: 'utf-8',
      signal 
    });
    
    // 文件写入成功后打印成功信息
    console.log('文件写入成功');
  } catch (err) {
    // 捕获并处理可能出现的错误
    if (err.code === 'ABORT_ERR') {
      // 如果是操作被中止的错误
      console.log('写入操作被中止');
    } else {
      // 其他类型的错误
      console.error('写入错误:', err);
    }
  }
}

// 调用异步函数
// 注意:这里没有调用controller.abort(),所以操作不会被提前中止
// 如果需要取消操作,可以在适当的位置调用controller.abort()
writeToFile();

2. 方法二:CallBack

const fs = require('fs')
fs.writeFile('./a.txt', '写进去的值', (err) => {
    if(!err) {
        console.log('写进去了');
    }
})

执行后的结果如图所示:

image.png

3.留下一个问题,如果我们想向文件里追加新的数据,应该怎么做呢?

5.模块化开发

模块化编程是一种将程序分解为独立、可重用模块的软件开发方法。
📖 推荐阅读

1. 为什么需要引入模块化?

举个例子:假如我们现在有两个js文件被同时引入在一个html文件中,并且这两个文件中定义了一个重名变量,那么当我们的html文件中使用到这个变量时,会发生什么呢?

例如:m1.js,如下:

var username = 'zhangsan';

m2.js,如下:

var username = 'wangwu';

index.html,如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./m1.js"></script>
    <script src="./m2.js"></script>
    <script>
        alert(username)
    </script>
</head>
<body>
    
</body>
</html>

在浏览器中打开,结果如图: 可见,alert弹出的是最后一次导入的,这对于团队合作来说及其不利,试想一下:你的username和同事的username冲突了,只是因为他的代码在你后面被引用了,然后你调用的时候,username就变成了他设定的值。

7580867b-3ad8-4a4a-ab1e-ff8f18de5a2a.png

在很长的一段时间里,大家都是通过自执行函数来解决这一问题,直到后来社区出现了模块化的解决方案:

  • CommonJS ---服务器端
  • ADM和UMD ---浏览器端

后来,在ES6发布之后,带来了官方的解决方案

  • ECMAScript Module

2. CommonJS(Node.js默认)

// 导出
module.exports = { functionA, variableB };

// 导入
const { functionA } = require('./moduleA');

//例如:
const { readFile } = require('node:fs/promises');
const { resolve } = require('node:path');

3. ES Modules(现代标准)

// 导出
export function functionA() {}
export const variableB = 42;

// 默认导出
export default mainFunction;

// 导入
import { functionA } from './moduleA.js';
import mainFunc from './mainModule.js';

// 例如:
import { writeFile } from 'node:fs/promises';
import { resolve } from 'node:path';

5. 用 http 模块搭建 HTTP 服务器

创建一个 server.js

const http = require('http');

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello, Node.js Server!');
});

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

✅ 运行

node server.js

常见错误"Port already in use"

  • 查找并终止占用端口的进程:

    lsof -i :3000  # 查找
    kill -9 PID    # 终止
    
  • 或者更改应用监听端口

📌 访问http://localhost:3000,你会看到 Hello, Node.js Server!

📖 推荐阅读

📹 视频教程