当前位置: 首页 > news >正文

学习记录:DAY33

前端学习之旅:Node.js 模块与 HTTP 服务

前言----------------------------------------
又是许久许久没有更新,在苦哈哈弄完期末,然后花一天时间把计算机网络课设写了之后。现在又即将回到前后端学习的状态。我想现在正处于一个调整期的状态。一个是随着 blog 的不断堆积,有必要把它们整理成更具有逻辑性的知识片。另一个是我需要了解当前前后端需要学习的路线,这样我可以有一个更明确地学习规划。言不在多,开始工作吧!


日程----------------------------------------
以后不能熬太多夜了,今天又是 9 点多起的床,这样太消耗身体了。今天早上的任务是整理 blog 的内容。又弄了一下午的课设,在我不懈努力之下,我终于是选择了放弃,麻了。
-----------6.23-------------
今天开始学 Nodejs,学了 buffer 和 fs 模块,来写写 blog
一放假早上就起不来了,得慢慢把时差调回来
晚上七点半了,把 http 模块学得差不多了,做做 blog


学习内容----------------------------------------

省流

  1. 分享一下近期有价值的内容
  2. Nodejs buffer 模块
  3. Nodejs fs 模块
  4. Nodejs http 模块

1. 分享一下近期有价值的内容

  • 用于学习 git 的可实践网站:Learn Git Branching 是一个非常实用的网站,可以帮助你通过实践来学习 Git 的各种操作。
  • 用于快速搭建虚拟局域网环境:Happynet 是一个基于 N2N 的工具,可以帮助你快速搭建虚拟局域网环境,非常适合需要远程访问和控制设备的场景。

2. Nodejs buffer 模块

用于内存的分配,以下是常见的创建方式:

  • 创建let buf = Buffer.alloc(10);
  • 非安全创建let buf_2 = Buffer.allocUnsafe(10);
  • 基于内容创建let buf_3 = Buffer.from("hello");
  • 获取的 buf 是一个数组let buf_4 = Buffer.from([85, 234, 231, 21, 85, 94]); console.log(buf_4[0].toString());

3. Nodejs fs 模块

用于文件操作,以下是常见的操作:

  • 导入模块const fs = require('fs');
  • 写入文件
    • 异步写入fs.writeFile('./test.txt', 'test12356', err => { if (err == null) { console.log('写入成功'); } });
    • 同步写入fs.writeFileSync('./test.txt', 'test2441');
    • 追加写入fs.appendFile('./test.txt', ',not my test', err => {});
    • 流式写入
      const ws = fs.createWriteStream('./test.txt', { flags: 'a' });
      ws.write("\r\n我");
      ws.write('\r\n是');
      ws.write('\r\n谁?');
      ws.end();
      
  • 异步特性:当程序进行到异步代码块时,会创建一个新线程处理异步代码,程序会继续向下执行。线程处理完异步代码后,通过回调函数压入任务队列中。这种异步特性在 Nodejs 非常常见。
  • 路径问题:使用 __dirname 可以获取当前的执行文件所在目录,通过 path 模块拼接路径:
    const path = require('path');
    const filepath = path.join(__dirname, 'test.txt');
    
  • 额外 API 说明
    API说明
    path.resolve拼接规范的绝对路径 常用
    path.sep获取操作系统的路径分隔符
    path.parse解析路径并返回对象
    path.basename获取路径的基础名称
    path.dirname获取路径的目录名
    path.extname获取路径的扩展名
  • 文件读取
    • 异步读取fs.readFile(filepath, (err, data) => { console.log(data.toString()); });
    • 流式读取
      const rs = fs.createReadStream(filepath);
      rs.on('data', chunk => { console.log(chunk.toString()); });
      
    • 读取 + 写入
      ws = fs.createWriteStream(path.join(__dirname, 'test2.txt'));
      rs.pipe(ws);
      
  • 重命名fs.rename(path.join(__dirname, 'test2.txt'), path.join(__dirname, 'test3.txt'), err => {});
  • 删除
    • fs.unlink(path.join(__dirname, 'test3.txt'), err => {});
    • 在 14.4 版本后添加了 rm 方法,两者的功能类似:fs.rm(path.join(__dirname, 'test3.txt'), err => {});
  • 文件夹操作
    • 创建文件夹fs.mkdir(path.join(__dirname, 'dir1'), err => {});
    • 递归创建fs.mkdir(path.join(__dirname, 'dir2/3/4/5'), { recursive: true }, err => {});
    • 读取文件夹fs.readdir(__dirname, (err, data) => { console.log(data); });
    • 删除文件夹
      • fs.rmdir(path.join(__dirname, 'dir1'), err => {});
      • 递归删除:fs.rm(path.join(__dirname, 'dir2'), { recursive: true }, err => {});
  • 获取资源的信息
    fs.stat(__dirname + '/test.txt', (err, data) => {console.log(data);
    });
    
    获取到的内容:
    Stats {dev: 0,mode: 33206,nlink: 1,uid: 0,gid: 0,rdev: 0,blksize: 4096,ino: 7318349395273121,size: 49,blocks: 0,atimeMs: 1750658164362.0237,mtimeMs: 1750652965429.8325,ctimeMs: 1750656700147.115,birthtimeMs: 1750652121205.9016
    }
    
    可以通过自定义输出来让内容更加格式化:
    fs.stat(__dirname + '/test.txt', (err, stats) => {console.log('文件信息:', {isFile: stats.isFile(), // 是否是文件isDirectory: stats.isDirectory(), // 是否是目录size: stats.size + ' bytes', // 文件大小createdAt: stats.birthtime, // 创建时间(Date 对象)modifiedAt: stats.mtime, // 修改时间(Date 对象)accessedAt: stats.atime, // 访问时间(Date 对象)});
    });
    
    结果如下:
    文件信息: {isFile: true,isDirectory: false,size: '49 bytes',createdAt: 2025-06-23T04:15:21.206Z,modifiedAt: 2025-06-23T04:29:25.430Z,accessedAt: 2025-06-23T05:56:04.362Z
    }
    

4. Nodejs http 模块

通过 Nodejs 来控制 http 相关的请求和响应内容:

  • 启动服务
    const http = require('http');
    const server = http.createServer((req, rep) => {//设置响应头 utf-8rep.setHeader('content-type', 'text/html;charset=utf-8');//设置响应体rep.end('你好');
    });
    server.listen(9000, () => {console.log('服务已经启动');
    });
    
  • 获取请求报文
    含义语法
    请求方法request.method
    请求版本request.httpVersion
    请求路径request.url
    URL 路径require('url').parse(request.url).pathname
    URL 查询字符串require('url').parse(request.url, true).query
    请求头request.headers
    请求体request.on('data', function(chunk){})
    request.on('end', function(){});
    比较常用的是请求方法和请求路径。获取 url 路径:
    const server = http.createServer((req, rep) => {...//实例化 URL 对象let url = new URL(req.url, 'http://127.0.0.1');//输出路径console.log(url.pathname);//输出查询字符串console.log(url.searchParams.get('key'));...
    });
    
    假设现在访问 http://localhost:9000/heyi?key=124,则控制台返回:
    /heyi
    124
    
  • 设置响应报文
    作用语法
    设置响应状态码response.statusCode
    设置响应状态描述response.statusMessage
    设置响应头信息response.setHeader('头名', '头值')
    设置响应体response.write('xx')
    />
    response.end('xxx')
    注意 response.end() 代表了响应处理的结束,会将响应结果返回给网页。一般设置内容用 response.write() 更加灵活一点,将 end 仅作为结尾。响应体是可以设置为一个文件 / 文件流的。通过设置响应体来加载 html 界面:
    const http = require('http');
    const fs = require('fs');
    const server = http.createServer((req, rep) => {let html = fs.readFileSync(__dirname + '/test.html');rep.end(html);
    });
    server.listen(9000, () => {});
    
  • 页面加载基本过程:网页的资源不是一次性全部获取的,以下面的为例子:
    <!DOCTYPE html>
    <html lang="en">
    <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><link rel="stylesheet" href="./test.css">
    </head>
    <body><h1>你好 bro</h1><button index="btn1" class="style">点我</button><script src="test.js"></script>
    </body>
    </html>
    
    首先我们手动加载了 html 资源,当浏览器发现 html 引用了 css,js 等资源时,它会向服务器发送对应的资源请求。如果是像我们之前那种写法,无论什么请求,都获取到了 html 资源,是肯定会出错的。我们需要动态的为资源请求进行相应请求体设置:
    const server = http.createServer((req, rep) => {let { pathname } = new URL(req.url, 'http://127.0.0.1');//拼接文件路径if (req.url == '/') pathname = '/test.html';let filePath = __dirname + pathname;//异步读取资源fs.readFile(filePath, (err, data) => {if (err) {rep.statusCode = 500;rep.end('文件读取失败');return;}rep.end(data);});
    });
    
  • 网页 URL 路径:网页中的 URL 主要分为两大类:相对路径与绝对路径。
    • 绝对路径
      形式特点
      http://atguigu.com/web直接向目标资源发送请求,容易理解。网站的外链会用到此形式
      //atguigu.com/web与页面 URL 的协议拼接形成完整 URL 再发送请求。大型网站用的比较多
      /web与页面 URL 的协议、主机名、端口拼接形成完整 URL 再发送请求。中小型网站
    • 相对路径:相对路径在发送请求时,需要与当前页面 URL 路径进行计算,得到完整 URL 后,再发送请求,学习阶段用的较多。例如当前网页 url 为 http://www.atguigu.com/course/h5.html
      形式最终的 URL
      ./css/app.csshttp://www.atguigu.com/course/css/app.css
      js/app.jshttp://www.atguigu.com/course/js/app.js
      ../img/logo.pnghttp://www.atguigu.com/img/logo.png
      ../../mp4/show.mp4http://www.atguigu.com/mp4/show.mp4
  • 设置资源类型:媒体(MIME)类型是一种标准,用来表示文档、文件或字节流的性质和格式。
    MIME 类型结构例子
    type/[subtype]text/html, text/css, image/jpeg, image/png, application/json
    HTTP 服务可以设置响应头 Content-Type 来表明响应体的 MIME 类型,浏览器会根据该类型决定如何处理响应体。下面是常见文件对应的 MIME 类型:
    文件类型MIME类型
    -------------------------------------
    htmltext/html
    csstext/css
    jstext/javascript
    pngimage/png
    jpgimage/jpeg
    gifimage/gif
    mp4video/mp4
    mp3audio/mpeg
    jsonapplication/json
    基于这个,我们可以自己规范化设置 mine 值:
    const mines = {html: 'text/html',css: 'text/css',js: 'text/javascript'
    };
    const server = http.createServer((req, rep) => {let { pathname } = new URL(req.url, 'http://127.0.0.1');//拼接文件路径if (req.url == '/') pathname = '/test.html';let filePath = __dirname + pathname;//获取文件后缀名 //.txt -> txtlet ext = path.extname(filePath).slice(1);//获取对应的类型let type = mines[ext];if (type) {rep.setHeader('content-type', type + ';charset=utf-8');} else {rep.end('类型获取失败');}//异步读取资源......
    });
    
    事实上,即使没有设置 mine,浏览器的嗅探机制也会根据返回的响应内容进行 mine 的设置。而中文字符集的设置,往往只需要设置 html 界面的,其他资源会基于 html 的字符集进行设置(尽管直接在网页读取资源时仍然是乱码):
    rep.setHeader('content-type', type + ';charset=utf-8');
    
http://www.lryc.cn/news/574818.html

相关文章:

  • 2025年渗透测试面试题总结-2025年HW(护网面试) 09(题目+回答)
  • HarmonyOS开发基础 --面向鸿蒙的TypeScript基础语法一文入门
  • 大模型本地部署,拥有属于自己的ChatGpt
  • 《仿盒马》app开发技术分享-- 兑换列表展示(68)
  • OSS安全合规实战:金融行业敏感数据加密+KMS自动轮转策略(满足等保2.0三级要求)
  • 如何使用MQTTX软件来进行MQTT协议的测试
  • # Python中等于号的使用
  • 逆向入门(7)汇编篇-mul指令的学习
  • DAY 41 简单CNN
  • 防御OSS Bucket泄露:RAM权限策略+日志审计+敏感数据扫描三重防护
  • DeepSeek智能总结 | 邓紫棋音乐版权纠纷核心梳理
  • 软件工程:从理论到实践,构建可靠软件的艺术与科学
  • 智慧家政数字化小程序开发:重构行业服务生态的创新引擎
  • 代码随想录|图论|01图论基础
  • 医药企业CMO研发管线管理专项介绍
  • 50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | MovieApp(电影卡片组件)
  • ArkTS与仓颉开发语言:鸿蒙编程的双子星
  • day41
  • 深入理解 BOM:浏览器对象模型详解
  • IoTDB的基本概念及常用命令
  • 【css】增强 CSS 的复用性与灵活性的Mixins
  • ArkUI-X通过Stage模型开发Android端应用指南(二)
  • 【软考高级系统架构论文】### 论软件系统架构评估
  • linux grep的一些坑
  • 接口自动化测试之 pytest 接口关联框架封装
  • Unity_导航操作(鼠标控制人物移动)_运动动画
  • matplotilb实现对MACD的实战
  • SQL关键字三分钟入门:UPDATE —— 修改数据
  • Camera Sensor接口协议全解析(五)SLVS-EC接口深度解析
  • Stable Diffusion 项目实战落地:打造完美海报的秘密武器 第二篇:边缘柔化、蒙版处理与图生图技术大揭秘!