ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Node.js入门指南:从环境搭建到核心概念与实战应用

Node.js入门指南:从环境搭建到核心概念与实战应用 1. 项目概述为什么Node.js是前端开发的“第二把钥匙”如果你是一名前端开发者可能已经习惯了在浏览器里用JavaScript写交互、调接口、做动画。但你是否想过如果能让这门语言跳出浏览器的“舒适圈”去操作文件、连接数据库、甚至搭建一个完整的服务器这就是Node.js带给我们的能力。它不是一个全新的语言而是让JavaScript运行在服务器端的一个运行时环境。简单来说它让前端开发者用自己最熟悉的语言去涉足后端开发的领域实现从前到后的“全栈”能力。很多人觉得后端开发门槛高要学Java、Python、Go但Node.js的出现让前端开发者能以极低的切换成本构建起自己的后端服务。这篇文章的目的就是帮你把这把“钥匙”稳稳地拿到手从零开始用最清晰、最详细的方式带你快速入门Node.js把基础打牢。我会按照核心要点来整理知识点让你看完就能动手而不是停留在概念层面。2. 环境准备从零搭建你的Node.js开发环境任何技术的学习第一步永远是搭建一个能跑起来的环境。对于Node.js来说这一步尤其重要因为它直接关系到后续所有命令和项目的运行。很多新手卡在第一步就是因为环境没配好。2.1 Node.js的安装与版本管理首先你需要安装Node.js。这里我强烈建议不要直接从官网下载安装包然后一路“下一步”就完事了。对于前端开发者一个更优雅、更专业的做法是使用Node版本管理器Node Version Manager, NVM。为什么用NVM想象一下你手头可能同时维护着两个项目一个老项目用的是Node.js 14另一个新项目要求Node.js 18。如果你只安装了其中一个版本切换起来会非常麻烦需要反复卸载重装。NVM就是为了解决这个问题而生的它允许你在同一台机器上安装并切换多个Node.js版本就像给你的电脑装了一个“版本开关”。Windows系统安装NVM对于Windows用户推荐使用nvm-windows。这是社区维护的版本非常稳定。卸载现有Node.js如果你之前通过安装包装过Node.js请先到控制面板的程序卸载功能里把它卸载干净避免冲突。下载安装包访问nvm-windows的GitHub发布页面下载最新的安装程序通常是nvm-setup.exe。安装过程运行安装程序。安装路径可以保持默认例如C:\Users\你的用户名\AppData\Roaming\nvm这个路径后续会用来存放不同版本的Node.js。安装程序会自动帮你配置系统环境变量。验证安装打开一个新的命令行窗口CMD或PowerShell输入nvm version。如果能看到版本号说明安装成功。macOS/Linux系统安装NVM对于macOS或Linux用户安装更简单通过终端命令即可完成。通常使用curl或wget下载安装脚本。curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash或者wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash安装完成后关闭并重新打开终端或者执行source ~/.bashrc或source ~/.zshrc取决于你用的shell使配置生效。然后输入nvm --version验证。使用NVM安装和管理Node.js安装好NVM后安装Node.js就变得非常简单。查看可用版本nvm list available会列出所有可安装的远程版本。安装指定版本比如安装最新的长期支持版LTS命令是nvm install 18.19.0版本号以当时最新LTS为准。NVM会自动下载并安装。安装最新版nvm install latest。查看已安装版本nvm list或nvm ls。切换使用版本nvm use 18.19.0。这个切换是临时的只对当前命令行窗口生效。设置默认版本nvm alias default 18.19.0。这样每次新开终端都会自动使用这个版本。注意在Windows PowerShell中执行npm脚本时可能会遇到“无法加载文件...因为在此系统上禁止运行脚本”的错误。这是因为PowerShell的执行策略限制。解决方法是以管理员身份打开PowerShell执行Set-ExecutionPolicy RemoteSigned然后选择Y。这是一个安全策略调整允许运行本地签名的脚本。2.2 验证安装与理解核心组件安装完成后我们需要验证Node.js是否真的可以用了并理解我们到底安装了些什么。打开你的命令行终端、CMD、PowerShell等依次输入以下命令node -v npm -v如果分别输出了Node.js和npm的版本号比如v18.19.0和10.2.3那么恭喜你环境安装成功了Node.js这就是我们安装的运行时本身。node -v查看的是Node.js解释器的版本。npm (Node Package Manager)这是随Node.js一同安装的包管理工具它是Node.js生态的基石。你可以把它想象成前端的“应用商店”或“软件仓库”。全世界数百万的开发者将自己写的可复用代码模块称为“包”或“package”发布到npm的公共仓库。当你开发项目时如果需要某个功能比如处理时间的moment库或者Web框架express不需要自己从头写只需要通过npm一条命令就能安装到自己的项目中。npm -v查看的就是这个包管理工具的版本。npx这也是一个很实用的工具它允许你直接运行本地或远程npm包中的命令而无需先全局安装这个包。例如有些脚手架工具你只需要临时用一次用npx就非常方便。至此你的开发环境已经就绪。有了Node.js和npm你就拥有了进入整个Node.js庞大生态系统的门票。3. Node.js核心概念与运行机制深度解析在开始写代码之前我们必须先理解Node.js的几个核心设计思想。这能帮你从根上明白为什么它适合某些场景而在另一些场景下可能不是最佳选择。3.1 事件驱动与非阻塞I/O高并发的秘密武器这是Node.js最著名、也最容易被误解的特性。我们用一个生活中的例子来类比。传统多线程/多进程模型阻塞I/O想象一家只有一位厨师的餐厅服务器。来了5位客人5个请求点了不同的菜。厨师只能一道一道做。做第一道菜时后面4位客人只能干等着即使他们点的菜很简单。这就是“阻塞”一个慢请求会卡住所有后续请求。为了解决这个问题餐厅服务器会雇佣多个厨师多线程/多进程每个厨师服务一位客人。但这带来了新的问题厨师线程成本高占用大量内存厨师间协调复杂线程同步、锁人多了厨房还挤上下文切换开销大。Node.js事件驱动模型非阻塞I/O还是那位厨师但他现在是个“事件驱动”的超级厨师。5位客人点完菜厨师不是立刻开始做而是把每道菜需要做的事情洗菜、切菜、烧水、炖煮拆分成一个个极小的“任务”并记在小本本事件队列上。然后他开始处理第一个任务比如给所有菜烧上水。在烧水等待的这几分钟里他并不会闲着等水开而是立刻去处理小本本上的下一个任务比如切第一道菜的配菜。当水烧开的“事件”发生时可能是由另一个系统“回调”通知他他再回来进行下一步操作放入食材。这样在I/O操作烧水、炖煮等需要等待的操作进行时厨师主线程的CPU时间并没有被浪费而是去处理其他任务了。在Node.js中这个“超级厨师”就是单线程的V8 JavaScript引擎。那个“小本本”就是事件队列Event Queue。而那个处理事件、调度任务的机制就是事件循环Event Loop。所有耗时的I/O操作如读写文件、网络请求、数据库查询都不会阻塞主线程而是提交给系统底层由C实现的libuv库去执行。当底层操作完成时会生成一个“完成事件”并附带结果这个事件和对应的回调函数会被放入事件队列。事件循环会不断地从队列中取出事件并执行对应的回调函数。带来的好处对于I/O密集型的应用比如Web服务器大部分时间在等待网络响应和数据库查询这种模型能用很少的系统资源一个主线程支撑非常高的并发连接。因为它没有线程创建和切换的开销。需要注意的坑正因为是单线程如果你在回调函数里执行了非常耗时的CPU密集型操作比如复杂的数学计算、大规模数据循环处理那么事件循环就会被这个操作阻塞期间所有新来的事件都无法被处理整个服务器就会“卡住”。这是Node.js的软肋。解决方案是将这类耗时任务交给工作线程Worker Threads或者拆分成更小的异步任务。3.2 模块系统代码组织的基石在浏览器中我们通过script标签引入JS文件全局变量容易污染。Node.js采用模块化来组织代码一个文件就是一个模块模块内的变量、函数默认是私有的不会影响到其他模块。CommonJS模块这是Node.js原生支持的模块规范使用require导入module.exports或exports导出。// calculator.js - 定义一个模块 function add(a, b) { return a b; } function subtract(a, b) { return a - b; } // 导出方式一导出一个对象 module.exports { add, subtract }; // 导出方式二逐个附加到 exports 上 // exports.add add; // exports.subtract subtract; // app.js - 使用模块 const calc require(./calculator.js); // 注意路径 console.log(calc.add(5, 3)); // 输出 8require是同步加载模块这符合Node.js最初服务端脚本的定位。ES Modules (ESM)这是ECMAScript标准的模块系统使用import和export语法。现在Node.js也提供了支持。// calculator.mjs 或 package.json 中设置 type: module export function add(a, b) { return a b; } export function subtract(a, b) { return a - b; } // app.mjs import { add, subtract } from ./calculator.mjs; console.log(add(5, 3));要使用ESM文件后缀需改为.mjs或者在package.json中设置type: module。ESM是异步加载的是未来的趋势但在Node.js生态中CommonJS目前仍占主流很多老包只支持CommonJS。混用时需要特别注意。核心模块与第三方模块Node.js自带了很多核心模块如fs文件系统、http网络、path路径处理无需安装直接require即可。第三方模块就是通过npm安装的包。3.3 包管理npm与package.jsonpackage.json文件是Node.js项目的“身份证”和“说明书”它位于项目的根目录记录了项目的元数据、依赖包、脚本命令等信息。初始化项目在项目文件夹下运行npm init它会以交互式问答的方式帮你创建package.json。如果嫌麻烦可以加-y参数快速生成默认配置npm init -y。package.json关键字段解析name: 项目名称。version: 项目版本遵循语义化版本规则主版本.次版本.修订号。scripts: 定义一些可以通过npm run script-name执行的命令。例如定义start: node app.js之后就可以用npm start来启动项目。dependencies:生产依赖。项目运行时必须的包比如express,lodash。通过npm install package-name --save或npm install package-name安装的包会记录在这里。devDependencies:开发依赖。仅在开发阶段需要的包比如测试框架jest、构建工具webpack。通过npm install package-name --save-dev安装。npm常用命令npm install package-name: 安装包到当前项目的node_modules文件夹并写入dependencies。npm install package-nameversion: 安装指定版本的包。npm install -g package-name: 全局安装包通常用于命令行工具如nodemon。npm update package-name: 更新某个包。npm uninstall package-name: 卸载包。npm list: 查看当前项目安装的包及其依赖树。npm audit: 检查项目依赖中的安全漏洞。实操心得永远不要把node_modules文件夹提交到Git仓库因为它体积巨大且可以通过package.json和package-lock.json完美复现。确保你的.gitignore文件里包含了node_modules/。package-lock.json这个文件非常重要它锁定了所有依赖包的确切版本保证了团队不同成员或在不同环境安装时得到完全一致的依赖树。请务必将它提交到仓库。4. 核心API实战从文件操作到HTTP服务器理解了核心概念我们开始动手写代码。Node.js的强大在于它提供了一系列直接调用系统能力的API。我们从最常用的文件操作和创建Web服务器开始。4.1 文件系统fs模块与磁盘对话fs模块提供了操作文件和目录的能力。它几乎所有函数都同时提供了同步和异步回调风格和Promise风格三种版本。异步回调风格这是最传统的方式函数最后一个参数是回调函数其第一个参数是错误对象errNode.js约定俗成的“错误优先”风格。const fs require(fs); // 读取文件 fs.readFile(./example.txt, utf8, (err, data) { if (err) { console.error(读取文件出错:, err); return; } console.log(文件内容:, data); }); // 写入文件 fs.writeFile(./output.txt, Hello Node.js!, utf8, (err) { if (err) { console.error(写入文件出错:, err); return; } console.log(文件写入成功); });同步风格函数名以Sync结尾会阻塞后续代码执行直到操作完成。通常只在程序启动初始化等少数场景使用。try { const data fs.readFileSync(./example.txt, utf8); console.log(data); } catch (err) { console.error(err); }Promise风格 (fs/promises)Node.js后期版本提供了基于Promise的API可以用async/await语法让异步代码看起来像同步一样清晰。const fs require(fs).promises; // 或者从 v14.8.0 可用 const fs require(fs/promises) async function fileOps() { try { const data await fs.readFile(./example.txt, utf8); console.log(data); await fs.writeFile(./output.txt, data \nAppended!); console.log(写入成功); } catch (err) { console.error(操作失败:, err); } } fileOps();个人建议在新项目中优先使用Promise风格 (fs.promises) 配合async/await代码结构更清晰避免了“回调地狱”。其他常用操作fs.existsSync(path): 同步检查文件/目录是否存在。fs.mkdir/fs.mkdirSync: 创建目录。fs.readdir: 读取目录内容。fs.stat/fs.statSync: 获取文件/目录状态信息如大小、创建时间。fs.rename: 重命名或移动文件/目录。fs.unlink: 删除文件。4.2 HTTP模块创建你的第一个Web服务器这是Node.js最经典的用途。无需任何第三方框架用核心的http模块就能创建一个Web服务器。const http require(http); // 创建服务器实例 const server http.createServer((req, res) { // req (IncomingMessage): 包含请求信息如URL、方法、请求头 // res (ServerResponse): 用于构建和发送响应 console.log(收到请求: ${req.method} ${req.url}); // 1. 设置响应头 res.setHeader(Content-Type, text/html; charsetutf-8); // 2. 根据请求URL返回不同内容 if (req.url /) { res.statusCode 200; // 状态码 200 OK res.end(h1欢迎来到Node.js服务器首页/h1); } else if (req.url /about) { res.statusCode 200; res.end(h1关于我们/h1p这是一个用原生Node.js创建的服务器。/p); } else { res.statusCode 404; // 状态码 404 Not Found res.end(h1404 - 页面未找到/h1); } }); // 启动服务器监听3000端口 const PORT 3000; server.listen(PORT, () { console.log(服务器运行在 http://localhost:${PORT}); });保存为server.js然后在终端运行node server.js。打开浏览器访问http://localhost:3000和http://localhost:3000/about你就能看到不同的页面内容了。代码解析http.createServer()接收一个请求监听器函数每次有HTTP请求进来这个函数就会被调用。函数接收两个对象req请求对象和res响应对象。我们通过req.url和req.method来判断用户请求的是什么。通过res.setHeader()设置响应头告诉浏览器返回的内容类型。通过res.statusCode设置HTTP状态码。最后用res.end()发送响应体并结束本次请求响应周期。server.listen()启动服务器绑定到指定的端口和主机。这个例子虽然简单但它揭示了Web服务器最本质的工作流程监听端口 - 接收请求 - 解析请求 - 生成响应 - 发送响应。所有复杂的Web框架如Express、Koa都是在这个基础上进行封装和扩展的。4.3 路径处理path模块与流Streampath模块处理文件路径的利器。不同操作系统路径分隔符不同Windows是\Linux/macOS是/直接用字符串拼接路径容易出错。path模块帮你解决这个问题。const path require(path); const filePath /user/docs/letter.txt; console.log(path.dirname(filePath)); // /user/docs 目录名 console.log(path.basename(filePath)); // letter.txt 文件名 console.log(path.extname(filePath)); // .txt 扩展名 console.log(path.join(/foo, bar, baz/asdf, quux, ..)); // /foo/bar/baz/asdf 智能拼接 console.log(path.resolve(wwwroot, static_files/png/, ../gif/image.gif)); // 解析为绝对路径流Stream处理大文件或连续数据的核心概念。想象一下你要把一个大水箱的水搬到另一个地方有两种方法1. 拿桶把水全部舀出来倒进另一个水箱对应readFile全部读入内存。2. 接一根水管让水一边流入一边流出对应流。显然第二种方法流更高效不占用大量内存。 Node.js的流有四种类型可读流Readable、可写流Writable、双工流Duplex、转换流Transform。文件读写、HTTP请求/响应、process.stdin/stdout都是流。const fs require(fs); // 用流的方式复制大文件 const readStream fs.createReadStream(./largefile.zip); const writeStream fs.createWriteStream(./largefile_copy.zip); readStream.pipe(writeStream); // pipe管道将可读流的数据自动导向可写流 writeStream.on(finish, () { console.log(文件复制完成); });pipe方法自动处理了数据流动和背压防止写入速度跟不上读取速度导致内存溢出是处理流的推荐方式。5. 异步编程进阶从回调地狱到优雅异步Node.js的异步特性是其优势但也带来了著名的“回调地狱”问题。代码层层嵌套难以阅读和维护。我们来看看解决方案的演进。5.1 回调函数与“回调地狱”最初的Node.js API大量使用回调函数。fs.readFile(a.txt, utf8, (err, dataA) { if (err) throw err; fs.readFile(b.txt, utf8, (err, dataB) { if (err) throw err; fs.writeFile(c.txt, dataA dataB, utf8, (err) { if (err) throw err; console.log(文件合并完成); // 如果再需要更多操作嵌套会更深... }); }); });这种金字塔形状的代码就是“回调地狱”Callback Hell。它让错误处理变得复杂流程控制困难。5.2 Promise异步编程的第一次革命Promise对象代表一个异步操作的最终完成或失败及其结果值。它可以将嵌套的回调转变为链式调用。const fs require(fs).promises; function readFilePromise(path) { // 实际上 fs.promises.readFile 已经返回Promise了这里仅为演示 return fs.readFile(path, utf8); } readFilePromise(a.txt) .then((dataA) { return readFilePromise(b.txt).then((dataB) dataA dataB); }) .then((combinedData) { return fs.writeFile(c.txt, combinedData, utf8); }) .then(() { console.log(文件合并完成); }) .catch((err) { // 用一个catch捕获链中任何错误 console.error(操作失败:, err); });代码结构变得扁平了一些但.then链仍然不够直观尤其是在需要用到前面结果的时候。5.3 Async/Await终极优雅方案async/await是建立在Promise之上的语法糖它让你能用写同步代码的方式写异步代码。const fs require(fs).promises; async function mergeFiles() { try { const dataA await fs.readFile(a.txt, utf8); const dataB await fs.readFile(b.txt, utf8); await fs.writeFile(c.txt, dataA dataB, utf8); console.log(文件合并完成); } catch (err) { console.error(操作失败:, err); } } mergeFiles();代码逻辑一目了然和同步代码几乎一样。async关键字用于声明一个函数是异步的await关键字用于等待一个Promise完成并返回其结果。try...catch可以像处理同步错误一样处理异步错误。重要注意事项await只能在async函数内部使用。调用一个async函数会立即返回一个Promise。如果你在顶层作用域非async函数内想使用await在Node.js的ESM模块中可以直接用在CommonJS中则需要用IIFE包裹(async () { await ... })();。不要滥用await如果多个异步操作之间没有依赖关系应该让它们并发执行而不是串行等待否则会丧失性能优势。// 错误串行总耗时 timeA timeB const resultA await fetchDataA(); const resultB await fetchDataB(); // 正确并行总耗时 ≈ max(timeA, timeB) const promiseA fetchDataA(); const promiseB fetchDataB(); const [resultA, resultB] await Promise.all([promiseA, promiseB]);Promise.all接收一个Promise数组当所有Promise都成功完成时返回一个结果数组。如果其中任何一个被拒绝整个Promise.all会立即被拒绝。6. 常用工具与开发调试技巧工欲善其事必先利其器。掌握一些核心工具和调试技巧能极大提升Node.js的开发效率。6.1 Nodemon开发时的自动重启神器在开发阶段每次修改代码后都需要手动停止 (CtrlC) 再重启 (node app.js) 服务器非常繁琐。nodemon可以监视文件变化自动重启Node.js应用。安装npm install -g nodemon全局安装方便所有项目使用或npm install --save-dev nodemon作为项目开发依赖安装。使用将启动命令node app.js替换为nodemon app.js。高级配置可以在项目根目录创建nodemon.json文件来配置监视的扩展名、忽略的目录等。{ watch: [src/, config/], ext: js,json, ignore: [node_modules/, dist/], exec: node ./src/app.js }现在当你保存代码文件时nodemon会自动重启应用浏览器刷新就能看到最新效果。6.2 调试从console.log到内置调试器console.log大法最简单直接但效率低需要反复添加和删除日志语句。内置调试器与Chrome DevToolsNode.js内置了强大的调试器并支持通过Chrome浏览器进行可视化调试。在启动命令中加入inspect标志node --inspect app.js。你会看到类似Debugger listening on ws://127.0.0.1:9229/...的输出。打开Chrome浏览器在地址栏输入chrome://inspect。在“Remote Target”区域你应该能看到你的Node.js应用点击下方的“inspect”链接。这会打开一个熟悉的Chrome开发者工具窗口但它是连接到你的Node.js进程的你可以在这里设置断点、单步执行、查看变量、调用栈就像调试前端JavaScript一样。VS Code集成调试如果你用VS Code调试体验更佳。点击左侧活动栏的“运行和调试”图标或按CtrlShiftD。点击“创建一个 launch.json 文件”选择“Node.js”。这会生成一个.vscode/launch.json配置文件。通常默认配置即可。在你的代码中点击行号左侧设置断点红点。按F5启动调试程序会在断点处暂停你可以使用调试工具栏继续、单步跳过、单步进入等进行调试并在侧边栏查看变量和调用栈。6.3 环境变量与配置管理应用在不同环境开发、测试、生产通常需要不同的配置比如数据库连接字符串、API密钥等。硬编码在代码中是极不安全的做法。正确的做法是使用环境变量。 Node.js通过process.env对象访问环境变量。使用dotenv管理环境变量安装包npm install dotenv在项目根目录创建.env文件务必将其加入.gitignoreNODE_ENVdevelopment DB_HOSTlocalhost DB_USERroot DB_PASSs3cr3t API_KEYyour_api_key_here在应用入口文件的最顶部加载配置require(dotenv).config(); // CommonJS // 或 import dotenv/config; // ESM在代码中通过process.env使用const dbConfig { host: process.env.DB_HOST, user: process.env.DB_USER, password: process.env.DB_PASS }; const isProduction process.env.NODE_ENV production;在生产环境中你不需要.env文件而是直接在服务器的系统环境变量中设置这些值例如在Linux中使用export命令或在Docker、云平台的控制台设置。7. 实战构建一个简单的静态文件服务器让我们综合运用以上知识构建一个比原生http模块例子更实用一点的工具一个简单的静态文件服务器。它可以读取指定目录下的HTML、CSS、JS、图片等文件并返回给浏览器。const http require(http); const fs require(fs).promises; const path require(path); const url require(url); // 定义静态资源目录 const PUBLIC_DIR path.join(__dirname, public); // 定义MIME类型映射 const MIME_TYPES { .html: text/html, .css: text/css, .js: application/javascript, .json: application/json, .png: image/png, .jpg: image/jpeg, .jpeg: image/jpeg, .gif: image/gif, .svg: image/svgxml, .ico: image/x-icon }; const server http.createServer(async (req, res) { // 解析请求的URL获取路径名 const parsedUrl url.parse(req.url); let pathname decodeURIComponent(parsedUrl.pathname); // 解码URL编码 // 默认首页 if (pathname.endsWith(/)) { pathname index.html; } // 构建实际文件路径 const filePath path.join(PUBLIC_DIR, pathname); console.log(请求文件: ${filePath}); try { // 1. 检查文件是否存在且可访问 await fs.access(filePath); // 2. 读取文件状态判断是否是目录如果是则找其下的index.html const stats await fs.stat(filePath); if (stats.isDirectory()) { // 重定向到目录下的index.html或者列出目录这里简单处理为404 res.statusCode 404; res.end(Directory listing not supported.); return; } // 3. 根据文件扩展名设置正确的Content-Type const ext path.extname(filePath).toLowerCase(); const contentType MIME_TYPES[ext] || application/octet-stream; res.setHeader(Content-Type, contentType); // 4. 使用流读取文件并发送避免大文件阻塞内存 const fileStream fs.createReadStream(filePath); fileStream.pipe(res); // 处理流错误如客户端中断连接 fileStream.on(error, (err) { console.error(流读取错误:, err); if (!res.headersSent) { res.statusCode 500; res.end(Internal Server Error); } }); } catch (err) { // 文件不存在或无权限访问 console.error(文件错误:, err.code); res.statusCode 404; res.setHeader(Content-Type, text/html; charsetutf-8); res.end(h1404 Not Found/h1p请求的资源 ${pathname} 不存在。/p); } }); const PORT process.env.PORT || 3000; server.listen(PORT, () { console.log(静态文件服务器运行在 http://localhost:${PORT}); console.log(静态资源目录: ${PUBLIC_DIR}); });项目结构your-project/ ├── server.js └── public/ # 静态资源目录 ├── index.html ├── style.css └── image.jpg运行与测试创建上述目录和文件在public/index.html里写点简单的HTML。运行node server.js。打开浏览器访问http://localhost:3000你应该能看到index.html的内容。尝试访问http://localhost:3000/style.css或图片地址它们也应该能被正确返回。这个例子涵盖了路径安全处理、MIME类型设置、错误处理、流式响应等多个核心知识点是一个非常好的综合练习。通过这个练习你会对Node.js如何处理HTTP请求和响应有更深刻的理解。在此基础上你可以尝试添加更多功能比如缓存控制、Gzip压缩、目录浏览等逐步把它完善成一个功能更全面的工具。
返回列表