本篇文章,学习记录于:尚硅谷🎢
本篇文章,并不完全适合小白,需要有一定的HTML、CSS、JS、HTTP、Web等知识及基础学习:
🆗,紧接上文,学习了:JavaScript 快速入门手册、新特性 之后,让我们来认识一个新的盆友 Node.JS
那是一个满是星星的夜晚,正把玩JS的我,想到一个问题,一个个单独的.JS文件,如何组合在一起成为一个项目
看网上好多大佬,使用 JS 像Java一样导包、写脚本、甚至连接服务器写后端….,这是如何做到的呢🤔❓经过一番查找认识了它🎉
Node.js是什么: 学习NodeJS首先就是要掌握 JavaScript(这里不介绍了)
Node.js(简称Node)是一个基于Chrome V8引擎的开源、跨平台的JavaScript运行时环境:
Node.js提供了一系列的库和工具,它扩展了 JavaScript 的用途,使得开发者能够编写服务器端应用程序,使JS更为强大和灵活;

最早JavaScript 主要用于网页开发—>前端页面交互,所以运行环境主要是浏览器
随着Node.js的出现,JavaScript获得了一种全新的运行环境,使其可以在服务器端运行:
二者环境有一些关键的区别,主要体现在它们的设计目标、提供的功能、核心模块等方面:
Node.js: 设计用于服务器端应用程序的运行环境,它的目标是提供高性能、非阻塞I/O的能力
global对象,核心模块,如HTTP、FS(文件系统)等require和module.exports来导入和导出模块浏览器环境: 设计用于在浏览器中执行JavaScript,实现网页交互和动态内容,主要关注于与用户界面的交互和浏览器特定的APl
window、DOM(文档对象模型)、BOM(浏览器对象模型)相关的API,例如document、windowimport和export语法,以及浏览器原生的模块系统二者都是JavaScript运行的地方,它们在设计目标、提供的功能、核心模块等方面有很大的差异,使得它们适用于不同的应用场景
基于 Node.js 提供的这些基础能,很多强大 的工具和框架如雨后春笋,层出不穷:
① 基于 Express 框架(http://www.expressjs.com.cn/),可以快速构建 Web 应用
② 基于 Electron 框架(https://electronjs.org/),可以构建跨平台的桌面应用
③ 基于 restify 框架(http://restify.com/),可以快速构建 API 接口项目
④ 读写和操作数据库、创建实用的命令行工具辅助前端开发、etc…
NodeJS 是一个服务应用程序,需要安装在服务器|设备上,使JavaScript可以直接在服务器上运行,不同的操作系统版本:Node官网🔗
各位,JYM可以到官网下载,也可以选择对应的版本:Other Dowloads其他版本🔗
区分 LTS 版本和 Current 版本的不同:
Current 版本中可 能存在隐藏的 Bug 或安全性漏洞,因此不推荐在企业级项目中使用 Current 版本的 Node
Windows安装Node服务,一般会默认配置环境变量:win+R 输入cmd:node -v 查看服务版本,确认安装成功!
随便编写一个:HelloWorld.JS
/** Node.js
* Node.js(简称Node)是一个基于Chrome V8引擎的开源、跨平台的JavaScript运行时环境
* 因为和浏览器的内置API不同所以存在一些区别,没有: windwo、document...对象 同时拥有自己的模块 */
console.log("node Hello World");在文件目录中:node 文件路径\名.js + Enter 回车 运行JS代码,对于执行时间长的命令使用:ctrl+c 终止运行
🆗到这里,恭喜你已经入门了! 🎉🎉 下面让我们深入了解Node.JS吧👇
JavaScript 语言没有用于读取或操作二进制数据流的机制,NodeJS提供了一个Buffer内置对象对二进制数据的操作:
固定长度的字节序列,每个元素的大小为 1字节byte=8bit二进制数据:因此:Buffer性能较好,可以直接对计算机内存进行操作/** Buffer的创建: */
const b1 = Buffer.alloc(10); //从内存上获取一段长度为10byte空间赋值Buffer
console.log(b1); //<Buffer 00 00 00 00 00 00 00 00 00 00> 十六进制
const b2 = Buffer.allocUnsafe(10); //随机获取内存上一段长度为10byte空间赋值Buffer,所以可能存在内存空间上的旧数据
console.log(b2); //<Buffer 59 8c 75 0b 6a 02 00 00 20 00> 有可能都是00 十六进制
//通过字符|数组...参数创建Buffer
const b3 = Buffer.from('Node.js');
const b4 = Buffer.from([11, 54, 68, 37]);
console.log(b3); //直接console则展示每个字节元素对应的ASCLL码值的十六进制
console.log(b4); //默认其实是UNICODE码表,ASCLL完全兼容UNICODE,所以查询直接查找ASCLLBuffer是一个类似于数组的对象,所以可以像数组一样操作元素的操作:
/** Buffer是一个类似于数组的对象,所以可以像数组一样操作元素的操作: */
const b3 = Buffer.from('Node.js');
// b3[0] = 110; //对应ASCLL小写n
console.log(b3[0]); //[下标] 获取字节元素
console.log(b3.length); //length Buffer内存字节长度
console.log(b3.toString()); //toString() 查看元素内容,默认 UTF-8编码格式
console.log(b3[0].toString(2)); //toString(2) 查看元素内容,并以二进制形式展示
//Buffer是一段固定长度连续的内存空间,因为是连续的内存空间所以快,也不方便删减内存元素...
/** Buffer关于中文的操作 */
const bus = Buffer.from('你好'); //中文一个字节占用3字节
console.log(bus);
console.log(bus.length); //6
console.log(bus.toString()); //你好Buffer的溢出: Buffer是一个类字节数组,我们都知道一个:1byte字节===8bit 也就是:2^8^ = 256 也就是:最大长度不能大于 255
const bu = Buffer.alloc(1);
bu[0] = 255;
console.log(bu); //<Buffer ff>
bu[0] = 256;
console.log(bu); //<Buffer 00> ???怎么编成0了
/** 对于超出字节长度是赋值并不会报错,而是进行溢出操作:赋值元素二进制大于8位的内容舍弃(仅保留从右-左8位长度bit)
* 255的二进制:1111 1111 =>保留结果: 11111111
* 256的二进制: 0001 0000 0000 =>保留结果: 00000000 */FS 全称为 file system 文件系统 ,是 Node.js 中的内置模块,可以对计算机中的磁盘进行操作
它提供了一组方法,使得你能够在文件系统中执行各种操作,如读取文件、写入文件、获取文件信息、创建目录等
FS是Node中的一个内置模块,内置|外部模块使用前都需要导入:require
require 是 Node.js 环境中的'全局'变量,用来导入模块,导入FS的模块名就是fs:不同模块导入,对应不同的模块名
const fs = require('fs'); //require导入FS模块: fs变量接收模块对象文件写入在计算机中是一个非常常见的操作:
语法:fs.writeFile(file, data,[options], callback)
{
//file: 相对|绝对文件路径: 文件不存在默认创建,路径不存在则目录拼接至文件名上...找不到盘符则报错;
fs.writeFile('.\www.txt','你好呀~',err =>{
//写入成功|失败执行函数,并传入错误对象:写入成功err=null
if (err) { return console.log('文件写入失败'); }
console.log('文件写入成功');
});
console.log('异步写入文件:不阻塞继续执行下面log');
}语法:fs.writeFileSync(file, data,[options]) 函数名比异步多了 Sync,参数和上述类似,同步方法没有回调函数
/** fs.writeFileSync(file, data,[options])
* 参数和上述类似:同步方法没有回调函数,报错就直接报错了... */
{
fs.writeFileSync('.\wsm.txt','你好呀Sync~');
console.log('同步写入阻塞程序文件写入完毕继续执行下面log');
fs.writeFileSync('.\wsm.txt',"\nflag参数实现文件追加...",{flag:'a'}); //{flag:'a'} 文件内容追加
}options 常用参数设置: flag 、 mode、 encoding …
r 只读模式、w 写入模式(默认)、a 追加模式utf-8(默认)、ascii、base64异步|同步Sync:
appendFile 作用是在文件尾部追加内容,语法与 writeFile 完全相同,writeXxx可以设置options➕追加内容📑
语法:fs.appendFile(file, data,[options],callback) 异步追加写入
{
//语法与writeFile语法完全相同
fs.appendFile('./www.txt','123\n',err=>{
if(err) { return console.log('文件写入失败'); }
console.log('文件写入成功'); });
fs.appendFile('./www.txt','456\n',err=>{
if(err) { return console.log('文件写入失败'); }
console.log('文件写入成功'); });
console.log('异步写入文件:不阻塞继续执行下面');
}语法:fs.appendFileSync(file, data,[options]) 同步追加写入
/** fs.appendFileSync(file, data,[options])
* 参数和上述类似:同步方法没有回调函数,报错就直接报错了... */
{
fs.appendFileSync('.\wsm.txt','123\n');
fs.appendFileSync('.\wsm.txt','456\n');
console.log('同步写入阻塞程序文件写入完毕继续执行下面log');
}流式写入: 和追加写入类似,流 更适合用于大文件的写入,性能优于常规的追加写入…
上述的:fs.appendFile 每次写入对象都要创建对应的文件连接、写入、回调处理,这对于大文件的写入会很麻烦、占用资源
{
//1.导入FS模块
//2.根据路径创建对应的文件流对象
const ws = fs.createWriteStream('./wsm.txt', { flags: 'a' });
ws.write('123\n'); //3.使用文件流对象写入文件...
ws.write('456\n');
ws.write('789\n');
ws.end(); //4.文件写入文本关闭文件流资源: nodeJS也会自动关闭资源
}程序打开一个文件是需要消耗资源的 ,流式写入可以减少打开关闭文件的次数
流式写入方式适用于大文件写入或者频繁写入的场景, writeFile 适合于写入频率较低的场景
文件读取顾名思义,就是通过程序从文件中取出其中的数据:
语法:fs.readFile(path,[options],callback)
/** fs.readFile(path,[options],callback)
* path: 路径+文件名,文件不存在则读取失败
* [options]: 可选参数配置,读取文件编码格式
* callback(err,data){ 回调函数当文件数据全读取,回调执行: data数据默认buffer类型 } */
{
//Demo:建议提前准备好要读取的文件;
fs.readFile('./wsm.txt', (err, data) => {
if (err) { return console.log('文件读取异常...'); }
console.log(data);
console.log(data.toString()); //buffer.toString(); 转UTF-8
});
}语法:fs.readFileSync(path,[options])
/** 同步读取:
* fs.readFileSync(path,[options]) 返回值:String|Buffer*/
{
const rb = fs.readFileSync('./wsm.txt');
const sb = fs.readFileSync('./wsm.txt', 'utf-8'); //[options]设置读取文件编码格式;
console.log(rb);
console.log(sb);
console.log('同步读取文件: 读取结束继续执行下面log');
}语法:fs.createReadStream(path,[options]) ==流式读取对于大文件的读取,节省内存,并且是异步的==
{
//1 引入FS模块
//2 根据文件路径创建文件读取流对象--这里需要更换自己的文件路径
const rs = fs.createReadStream('./resource/男娘.MP3'); //提前准备大文件: 图片/视频...
//3 给读取流对象 绑定data事件
rs.on('data', chunk => {
console.log(chunk); //默认块: 65536字节byte => 64KB 最后一块不满足会比较小;
//这样每次读取一块数据,对每块数据进行操作用完即回收减少内存开销,提高程序性能...
});
//4 [可选]:文件读取完成
rs.on('end', () => { console.log('文件读取结束'); })
}普通读取 和 流式读取的区别:
它会一次性地读取文件的全部内容,然后执行回调函数或返回结果它可以分段地读取文件,不需要等待文件完全加载到内存中流式读取可以节省内存空间,提高性能,适合处理大文件或网络数据
对于大文件,普通读取一次性读取是直接读进内存的,如果文件1G则等于1G内存,==很容易内存溢出⛲==
在 Node.js 中,我们可以使用 unlink 或 unlinkSync 来删除文件,node14.4新增:rm|rmSync 语法:
删除时候要确认要删除的文件存在,不然会报错:Error: ENOENT: no such file or directory
fs.unlink(path, callback)fs.unlinkSync(path)rm它有一些额外的选项|并支持对文件夹操作:
recursive (递归删除),force (强制删除),maxRetries (重试次数),retryDelay(重试间隔时间) …
fs.rm(path,[options],callback)fs.rmSync(path,[options])/** 文件的删除:
* fs.unlink(path, callback) 同步删除 如果路径文件不存在则报错
* fs.unlinkSync(path) 异步删除 */
{
fs.unlink('./wsm.txt', err => {
if (err) return console.log('unlink删除失败');
console.log('unlink删除成功');
});
//同步方法并没有回调函数,原地返回相应结果,所以需要传统try-catch捕获异常
try {
fs.unlinkSync('./wsmm.txt');
console.log('unlinkSync删除成功');
} catch (error) { console.log('unlinkSync删除失败'); }
}
/** node14.4新增删除方法
* rm|rmSync 异步|同步的删除方法... */
{
/** 吐槽一下啊:本人想要复刻重复删除成功的过程始终没有实现,求路过的大佬指点一下: */
fs.rm('./wsm', { recursive: true ,maxRetries: 50, retryDelay: 100 }, err => {
if (err) return console.log('rm删除失败');
console.log('rm删除成功');
});
try {
fs.rmSync('./wsmm.txt');
console.log('rmSync删除成功');
} catch (error) { console.log('rmSync删除失败'); }
}recursive: trueNode.js 中,我们可以使用 rename 或 renameSync 来移动|重命名或文件夹
fs.rename(oldPath, newPath, callback)fs.renameSync(oldPath, newPath)newPath 文件路径不变就是重命名,文件路径改变就是剪切
/** 文件的重命名|移动
* fs.rename(oldPath, newPath, callback) 异步
* fs.renameSync(oldPath, newPath) 同步
* oldPath :表示要修改的文件资源,不存在则报错;
* newPath :表示修改后的文件地址,单纯文件名发生改变——>重命名,文件路径|名改变——>剪切|重命名; */
{
//异步重命名|移动
fs.rename('./wwsm.txt', './www/wsmup.txt', err => console.log(err)); //移动的路径要存在则报错
//同步重命名|移动
// fs.renameSync('./wwsm.txt', './www/wsmup.txt');
}对于文件的Copy 业务拆分就是:读+写:要Copy A文件,FS读取出来,创建写入新 B文件,就是Copy的过程~
需要注意: 读写文件的过程中,读写流比较节省内存,且效率高…. 对于大文件的Copy,==建议使用流式操作==
借助 Node.js 的能力,我们可以对文件夹进行 创建 、 读取 、 删除 等操作
fs.mkdir(path[, options], callback) 异步创建fs.mkdirSync(path[, options]) 同步创建/** 创建文件夹
* path: 指点创建的文件路径,文件存在则报错
* options: 可选配置完成特殊操作
* callback: 回调函数... */
fs.mkdir('./wsm',err=>{ console.log(err); }); //同级目录创建wsm文件夹,如果存在会报错;
fs.mkdir('./wsm/sss',{recursive:true},err=>{ console.log(err); }); //配置:可创建多级目录 目录存在并不会报错;fs.readdir(path,[options], callback) 异步读取: 回调函数有两个形参;fs.readdirSync(path,[options]) 同步创建: 函数返回一个数组;//回调函数接收两个参数: err(异常有值|无异常null)、data(数组数据结构:返回当前路径下所有文件名|目录)
fs.readdir('./wsm',(err,data)=>{
if(err) return console.log(err);
console.log(data);
});fs.rmdir(path[, options], callback) 异步删除fs.rmdirSync(path[, options]) 同步删除// 默认:文件夹非空不允许删除
// fs.rmdir('./wwww',err=>{ console.log(err); });
// 设置{recursive:true}递归true 则文件非空|多级目录可以删除;
fs.rmdir('./wwww',{recursive:true},err=>{ console.log(err); }); {recursive:true} 随着node的版本上升后面可能会被淘汰 建议后面删除文件目录操作使用:fs.rm(...)
在 Node.js 中,我们可以使用 stat 或 statSync 来查看资源的详细信息
fs.stat(path,[options], callback) 异步查看状态: 回调函数有两个形参;fs.statSync(path,[options]) 同步查看状态: 函数返回一个对象;//回调函数接收两个参数: err(异常有值|无异常null)、data(对象数据结构:返回当前文件资源的状态对象)
fs.stat('./resource/男娘.MP3',(err,data)=>{
if(err) console.log(err);
console.log(data);
});
//同步获取文件资源信息:——方法返回文件资源对象
// const statFile = fs.statSync('./resource/男娘.MP3');
// console.log("是否文件夹:" + statFile.isFile());来查看资源的详细信息,返回一个资源对象,常用属性有:
stats.nlink:文件的硬链接数
stats.mode: 文件的权限和类型
stats.ino: 文件的 inode 号
stats.gid: 文件的所有者的组标识符
stats.uid: 文件的所有者的用户标识符
stats.size: 文件的大小,以字节为单位
stats.dev: 文件所在的设备的数字标识符
stats.blocks: 文件占用的文件系统块的数量
stats.atime: 文件的上次访问时间的 Date 对象
stats.mtime: 文件的上次修改时间的 Date 对象
stats.blksize: 用于 I/O 操作的文件系统块的大小
stats.ctime: 文件的上次状态变更时间的 Date 对象
stats.atimeMs: 文件的上次访问时间的时间戳,以毫秒为单位
stats.mtimeMs: 文件的上次修改时间的时间戳,以毫秒为单位
stats.rdev: 如果文件是特殊文件,表示其设备的数字标识符
stats.ctimeMs: 文件的上次状态变更时间的时间戳,以毫秒为单位
stats.birthtime: 文件的创建时间的 Date 对象
stats.birthtimeMs: 文件的创建时间的时间戳,以毫秒为单位除了这些属性名,fs.Stats 对象还提供了一些方法,用于判断文件或目录的类型:
stats.isFile(): 如果文件是文件,返回 true
stats.isDirectory(): 如果文件是目录,返回 true
stats.isFIFO(): 如果文件是 FIFO,返回 true
stats.isSocket(): 如果文件是套接字,返回 true
stats.isBlockDevice(): 如果文件是块设备,返回 true
stats.isSymbolicLink(): 如果文件是符号链接,返回 true
stats.isCharacterDevice():如果文件是字符设备,返回 truefs 模块对资源进行操作时,路径的写法有两种:相对路径|绝对路径
. 或 ..开头,表示当前目录或上级目录/ 或 盘符开头,表示系统的根目录或分区//相对路径指相对于某个基准路径的路径,它通常以 . 或 .. 开头,表示当前目录或上级目录
fs.mkdirSync('./newdire', { recursive: true }); //./创建同级
fs.mkdirSync('../newdire', { recursive: true }); //../创建上一级
fs.mkdirSync('../newdire/dire', { recursive: true }); //上一级递归创建多级目录
//绝对路径指从根目录开始的完整的路径,它通常以 / 或 盘符 开头,表示系统的根目录或分区
fs.mkdirSync('D:/newdire0', { recursive: true }); //D盘创建
fs.mkdirSync('C:/newdire0', { recursive: true }); //C盘创建(系统盘可能因为权限不足获取失败!)
fs.mkdirSync('/newdire2', { recursive: true }); //对于不同的操作系统无法固定盘符: / 默认系统盘路径Node.js中的相对路径:,指的是命令行的工作目录 ,而并非是文件的所在目录:
xx.js文件 代码中的相对路径,相对的是:node xxx/xxx/xx.js node 命令执行所以在的路径!Node.js 相对路径会因为,node 启动命令而变化,所以对于一些情况会很麻烦,这时候就可以使用:__dirName|__fileName
__dirName|__fileName 是 Node.js 中每一个模块的局部变量 ,每个模块都有自己的 __filename 和__dirName
它表示当前执行脚本所在的目录的绝对路径:
//获取当前文件的绝对路径|+文件名,实际开发中通过用这个来规定路径完善
console.log(__dirname); //C:\Users\wsm17\Desktop\ls\NodeStudy\01FS模块
console.log(__filename); //C:\Users\wsm17\Desktop\ls\NodeStudy\01FS模块\09相对绝对路径.jsNode.js中的 path 目录是一个模块,它提供了一些工具函数
用于处理文件与目录的路径,它可以根据不同的操作系统,使用 Windows 或 POSIX 风格的路径
/** Path系统路径模块 */
const fs = require('fs');
const path = require('path');
//获取当前文件的绝对路径|+文件名,实际开发中通过用这个来规定路径完善
console.log(__dirname); //C:\Users\wsm17\Desktop\ls\NodeStudy\01FS模块
console.log(__filename); //C:\Users\wsm17\Desktop\ls\NodeStudy\01FS模块\09相对绝对路径.js
/** 上述__xxXX局部属性获取的路径是 \ 而我们正常使用的是 /
* 虽然不影响正常使用(系统会自动进行处理操作系统识别的路径) 但这样对路径进行拼接就会不可读 */
{
console.log(__dirname+'/wsm'); //C:\Users\wsm17\Desktop\ls\NodeStudy\01FS模块/wsm
}Path就是专门为了解决这种问题而出现的:内部有很多方法:
/** Path常用函数: */
{
//path.sep 是 path模块中的一个属性,用于表示操作系统的路径分隔符
console.log(path.sep); //不同的操作系统上文件路径的分隔符是不同的: windows是\ 在 Linux|Unix是/
//path.resolve([...paths]) 解析为绝对路径,相对于当前工作目录
console.log(path.resolve(__dirname,'./wsm')); //C:\Users\wsm17\Desktop\ls\NodeStudy\01FS模块\wsm
console.log(path.resolve(__dirname,'../wsm')); //C:\Users\wsm17\Desktop\ls\NodeStudy\wsm
//path.parse(pathString) 将路径解析为对象包含:目录、根目录、基本名称、扩展名等信息
console.log(path.parse('/path/wsm/qq540.txt'));
}方法 | 描述 |
|---|---|
| 连接路径片段,形成规范化路径。 |
| 解析为绝对路径,相对于当前工作目录。 |
| 将路径解析为对象,包含目录、根目录、基本名称、扩展名等信息。 |
| 返回文件名部分,可去除指定扩展名。 |
| 返回目录名。 |
| 返回扩展名。 |
Node.js 中最重要的一个模块,使node可以实现服务器的效果,使JS可以完成后端功能,而这需要掌握了解一些网络知识,下面简单介绍一下:
HTTP 是超文本传输协议,也就是HyperText Transfer Protocol,是一种基于TCP/IP的应用层通信协议,它可以拆成三个部分:协议、传输、超文本
「超文本」就是超越了普通文本的文本,文字、图片、视频等的混合体,最关键有超链接,能从一个超文本跳转到另外一个超文本
HTML 就是最常见的超文本,它本身只是纯文字文件,但内部用很多标签定义了图片、视频等的链接,经过浏览器解释,呈现的就是有画面的网页了
HTTP协议就是浏览器和服务器之间的互相通信的规则:
request请求报文response响应报文 报文:可以简单理解为就是一堆字符串注意: HTTP 并不仅仅从互联网服务器传输超文本到本地浏览器协议,HTTP也可以是==「服务器🖥< -- >服务器🖥」==
一般为了方便监听我们需要一些工具:Fidder 安装在客户端的一个服务可以监听所有的请求~、 浏览器+F12开发者模式
HTTP请求报文由三部分组成:请求行、请求头、空行、请求体

请求行: GET https://www.sogou.com/ HTTP/1.1 由: 请求方法 请求URL 请求版本号
GET POST PUT DELETE ...https://www.sogou.com/ 由:协议、域名、端口、资源路径、参数路径... 组成https search.jd.com 443 /search ?keyword=oneplus&psort=3
协议名 主机名 端口号 资源路径 查询字符串
协议名scheme: 指定访问资源时要使用的协议,例如 http、https、ftp 等
主机名host: 指定服务器的主机名或 IP 地址,通常情况下会使用域名代替
端口号port: 指定服务器的端口号,如果未指定则使用协议的默认端口
资源路径path: 指定资源在服务器上的路径,用于定位具体的资源地址
查询字符串query: 包含了请求参数,通常用于向服务器传递额外的信息,服务器判断返回相应的结果
HTTP/1.0, HTTP/1.1, HTTP/2.0 等Connection: keep-alive 头部支持持久连接Quick UDP Internet Connections 减少连接的时延HTTP 请求头(HTTP Request Headers)是包含在客户端向服务器发送的 HTTP 请求中的元数据信息
这些头部提供了有关请求的额外信息,帮助服务器理解如何处理请求和提供适当的响应,以下是一些常见的 HTTP 请求头及其作用:
Host: 指定服务器的域名和端口号,标识请求的目标服务器Connection: 控制是否保持持久连接Accept: 指定客户端可以接受的响应内容类型Accept-Language: 指定客户端接受的自然语言、Accept-Encoding: 指定客户端支持的内容编码,如 gzip、deflateAuthorization: 包含用于身份验证的信息,通常在需要访问受保护资源时使用Cookie: 包含客户端的 Cookie 信息,用于保持状态和会话Referer: 表示请求的来源,即引导用户访问当前页面的页面 URLUser-Agent: 标识发起请求的客户端,通常包括浏览器、操作系统Content-Type: 指定请求体的媒体类型,仅在请求中包含主体时使用HTTP 请求体是包含在 HTTP 请求中的可选部分,用于向服务器发送数据
请求体的使用取决于请求的性质和所需传递的数据类型,==请求体的内容格式是非常灵活的,可以设置任何内容==
表单数据:
Content-Type: application/x-www-form-urlencoded
Content-Type: multipart/form-data
key1=value1&key2=value2JSON 数据:
Content-Type: application/json
{
"key1": "value1",
"key2": "value2"
}文件上传(多部分数据):
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="example.txt"
Content-Type: text/plain
... contents of the file ...
------WebKitFormBoundary--空行,字面意思,用于区别请求头 请求体
HTTP 响应报文 和请求报文类似: HTTP 响应报文是由服务器返回给客户端的信息,它包含了有关请求的结果的详细信息
HTTP 响应报文由以下三个部分组成: 响应行、响应头 和 响应体

响应行由三部分组成: <u>HTTP/1.1</u> <u>200</u> <u>OK</u> ==<u>HTTP版本号</u> <u>响应状态码</u> <u>响应状态消息</u>==
HTTP-Version: 指定服务器使用的 HTTP 协议版本,常见的: HTTP/1.0、HTTP/1.1、HTTP/2.0、HTTP/3.0Status-Code: 用于表示服务器对请求的处理结果,200 成功,404 未找到资源,500 服务器内部错误…100 Continue 服务器已经接收到客户端的部分请求,但还没有最终的响应200 OK 表示成功、201 Created 请求已经被成功处理,并在服务器上创建了新的资源301 Moved Permanently 表示永久重定向、304 Not Modified 表示资源未被修改,可以使用缓存的版本400 Bad Request 服务器无法理解客户端的请求,请求语法错误、404 Not Found 表示未找到资源500 Internal Server Error 服务器内部错误、502 Bad Gateway 服务器网关代理无效响应Reason-Phrase: 提供对状态码的简要描述,OK 表示成功,Not Found 表示未找到资,Found 表示临时移动状态消息通常是标准的英文短语,用于简要描述与相应状态码相关的情况,为了让开发人员和网络管理员更容易理解服务器对请求的响应结果
响应头与请求头类似,HTTP响应头是包含在 HTTP 响应中的元数据信息,提供了关于响应的详细信息
响应头提供有关响应的重要信息,帮助客户端正确处理响应体并执行相应的操作,实际应用中,可以根据需要添加或使用不同的响应头:缓存 安全性 内容解析
这些头部通常位于 HTTP 响应的起始部分,即状态行之后,空行之前,响应头由一个字段名和一个字段值组成,以下是一些常见的HTTP响应头及其作用:
Location: 在发生重定向时,指定新的资源位置 Location: https://www.example.com/new-locationSet-Cookie: 响应中设置Cookie,在客户端和服务器之间传递状态信息Set-Cookie: username=JohnDoe;path=/Content-Type: 指定了响应体的媒体类型,告诉客户端如何解析响应体 Content-Type: text/html; charset=utf-8Cache-Control: 控制缓存行为,指示响应是否可以被缓存以及缓存的有效期等。 Cache-Control: max-age=3600, publicContent-Length: 指定了响应体的长度(以字节为单位)Content-Length: 1024Server: 指定了响应中使用的服务器软件的信息 Server: Apache/2.4.41 (Unix)Date: 指定了响应的日期和时间 Date: Wed, 01 Dec 2021 12:00:00 GMTETag: 标识资源的唯一标识符,用于支持条件请求 ETag: "abc123"响应体与请求体类似,HTTP 响应体是包含在 HTTP 响应中的主体部分,包含了服务器返回给客户端的实际数据
Content-Type 等信息来正确解析和处理响应体的内容HTML 文档: Content-Type:text/html
<!DOCTYPE html>
<html>
<head> <title>Example HTML</title> </head>
<body> <h1>Hello, World!</h1> </body>
</html>JSON 数据: Content-Type:application/json
{ "name": "John Doe", "city": "Example City"}纯文本数据: Content-Type: text/plain
This is a plain text response.二进制数据(图片): Content-Type:image/jpeg 二进制数据,通常无法在文本中显示
Node.js 中的 http 模块是用于创建 HTTP 服务器和客户端的核心模块
通过该模块,你可以轻松地创建一个简单的 HTTP 服务器,处理 HTTP 请求和响应
const http = require('http'); //require导入HTTP模块: 和FS一样Node.JS使用模块都需要进行导入http.createServer 函数创建一个服务器对象:方法接受一个回调函数,这个回调函数会在每次有 HTTP 请求时被调用,回调函数接收两个参数
const server = http.createServer((request, response) => {
response.end('Hello HTTP Server');
});服务器对象.listen(port,()=>{ 服务启动 }) 函数启动服务,并监听port端口请求
//使用 server服务器对象监听端口,启动服务:
server.listen(5400, () => {
//服务启动成功的描述信息;
console.log('node Server 启动!!');
})🆗,Node创建本地服务器,并启动端口监听完成:浏览器 http://127.0.0.1:5400/ 就可以请求到了server服务器并获取响应,F12可以更方便查看
HTTP 协议默认端口是 80,HTTPS 协议的默认端口是 443,HTTP 服务开发常用端口有 3000, 8080,8090,9000 等
当服务启动后,更新代码必须重启服务才能生效,监听服务 ctrl + c 停止服务🛑

一、响应内容中文乱码问题: Node.js HTTP响应默认是UTF-8,但有时候浏览器默认编码格式是ISO-8859-1
所以为了避免,中文乱码,在服务器响应的时候,可以通过response.setHeader指定响应的编码格式
response.setHeader('content-type', 'text/html;charset=utf-8');二、服务监听端口启动报错: Error: listen EADDRINUSE: address already in use :::XXX|错误:监听EADDRINUSE:地址已在使用:::XXX
当前server服务器对象listen监听的端口已经被占用… 如何解决(・∀・❓
资源资源监视器-网络-侦听端口 找到占用端口的程序|PID,到任务管理器-详细信息PID查询对应服务进行关闭

http.createServer 函数创建一个服务器对象,方法接受一个回调函数,回调函数接收两个参数: request|response
request获取请求行|请求头
request.url: 获取请求的 URLrequest.method: 获取请求的 HTTP 方法request.httpVersion: 获取请求的 HTTP 版本request.headers.xxxx: 获取请求头的对象,可以通过属性名获取特定的请求头值//导入HTTP模块
const http = require('http');
//创建服务器对象
const server = http.createServer((request, response) => {
//request获取请求行
console.log(request.url); //获取请求的 URL
console.log(request.method); //获取请求方法: GET、POST...
console.log(request.httpVersion); //获取请求的HTTP版本: 1.1 2.0
//request获取请求头:
console.log(request.headers); //headers是对象结构属性|值形式展示
console.log(request.headers.host);
console.log(request.headers.connection); //headers.connection 获取对应的属性数值
//response设置响应报文
response.setHeader('content-type', 'text/html;charset=utf-8');
response.end('Hello HTTP Server 服务响应!');
});
//创建监听端口,启动服务:
server.listen(5400, () => {
console.log('node Server 启动!!');
})request获取请求体:
Node.js 中获取 HTTP 请求体的方式多样化:Web 框架、HTTP 服务器、内置HTTP模块
内置的http模块:可以通过req请求对象监听 data | end 事件获取请求体
request.on('data', function(chunk){}) 监听 data 事件,当有请求数据可用时,会触发回调函数,将数据块附加到 data 变量上 每当接收到请求体数据的时候,都会触发 data 事件,事件可以被多次触发,每次触发时提供一个数据块chunk 设计理由:👇
data 事件允许你在接收到每个数据块时执行相应的处理,而不必等到整个请求体接收完毕request.on('end', function(){}); 监听 end 事件,当请求体的所有数据都接收完毕时,触发回调函数,获取完整的请求体;/** 获取HTTP请求报文 */
const http = require('http');
/** request获取请求体:
* 设置参数body接收请求体
* 绑定data事件:因为请求体大小不确定避免内存过大溢出,分块传输多次监听
* 绑定end 事件:当请求体的所有数据都接收完毕时,触发回调函数,获取完整的请求体 */
const server = http.createServer((request, response) => {
let body = '';
request.on('data', chunk => { body += chunk });
request.on('end', () => { console.log(body); });
//response设置响应报文
response.setHeader('content-type', 'text/html;charset=utf-8');
response.end('Hello HTTP Server 服务响应!');
});
//使用 server服务器对象监听端口,启动服务:
server.listen(5400, () => {
console.log('node Server 启动!!');
})⚠️⚠️注意事项:
GET请求 而GET没有请求体,建议使用:HTML、Postman测试Web Http请求的形式有很多:
application/x-www-form-urlencoded 格式的请求体,通常来自 HTML 表单提交,可以使用内置的 querystring 模块来解析请求体数据application/json 格式的请求体,通常是通过 AJAX 或其他客户端发送 JSON 数据,可以使用 JSON.parse 解析 JSON 数据如何处理中文乱码... 目前了解即可👍🆗,上面了解了如何从请求报文种获取,请求行|头|体,就可以根据不同的请求体,来做出很多的响应,而 GET请求并不方便携带请求体:
所以,我们还可以从请求路径上获取:路径信息|参数字符串来处理多种响应: 如下我们常见的Demo:
http://127.0.0.1:5400/login 客户端请求登录页面http://127.0.0.1:5400/register 客户端请求注册页面http://127.0.0.1:5400/register?name=xxx&password=xxx 客户端请求带参注册请求NodeJS HTTP解析请求路径——方式一: 导入url模块解析,简单介绍一下url模块…
url.parse('url') 方法可以将一个 URL 字符串解析成一个 URL 对象,对象包含了 URL 的各个组成部分
url.parse('url',true) :当第二个参数为 true 时,url.parse() 方法会将查询字符串解析为一个对象,查询参数的键值对
/** 模块导入 */
const http = require('http');
const url = require('url');
/** HTTP解析请求路径: url.parse()方法可以将一个URL字符串解析成一个对象,包含了URL的各个组成部分 */
const server = http.createServer((request, response) => {
response.setHeader('content-type', 'text/html;charset=utf-8'); //解决中文乱码;
let res = url.parse(request.url, true);
console.log(res.pathname) //获取请求路径
console.log(res.query) //获取请求参数对象
if (res.pathname == '/login') {
response.end('login登录页面');
} else if (res.pathname == '/register') {
if (Object.keys(res.query).length !== 0) response.end(JSON.stringify(res.query));
else response.end('register注册页面');
} else { response.end('未知路径请求'); }
});
//使用 server服务器对象监听端口,启动服务:
server.listen(5400, () => { console.log('node Server 启动!!'); })NodeJS HTTP解析请求路径——方式二: 实例化URL的对象解析;
new URL() 方法在浏览器环境和 Node.js 环境中的行为可能有一些差异,具体取决于具体的使用场景
/** 实例化URL的对象解析 */
{
// URL 字符串
const urlString = 'https://www.example.com:8080/path?query=123#fragment';
// 使用 url.parse() 方法解析 URL 字符串并生成 URL 对象
const parsedUrl = new URL(urlString);
// 输出 URL 对象的属性
console.log('hash:', parsedUrl.hash); // '#fragment'
console.log('protocol:', parsedUrl.protocol); // 'https:'
console.log('port:', parsedUrl.port); // '8080'
console.log('host:', parsedUrl.host); // 'www.example.com:8080'
console.log('hostname:', parsedUrl.hostname); // 'www.example.com'
console.log('pathname:', parsedUrl.pathname); // '/path'
console.log('search:', parsedUrl.search); // '?query=123'
console.log('searchParams:', parsedUrl.searchParams); // URLSearchParams{ 'query' => '123' } 对象
}http.createServer 函数创建一个服务器对象,方法接受一个回调函数,回调函数接收两个参数: request|response
在Node.js 中,当你使用 http 模块创建一个服务器时,如果不显式设置响应头,Node会提供一组默认的响应头,Node也提供属性根据需求自定义
res.statusCode 获取或设置 HTTP 响应的状态码,必须数字res.statusMessage 获取或设置 HTTP 响应的状态消息,必须英文res.getHeader(name) 获取指定响应头的值,实例:res.getHeader('Content-Type');res.setHeader(name, value) 设置响应头的值,可以使用该方法多次设置多个响应头,示例:res.setHeader('Content-Type', 'text/plain');/** HTTP 设置响应报文 */
const server = http.createServer((request, response) => {
//设置响应头|行:
response.statusCode = 540;
response.statusMessage = 'WSM'; //随机设置响应:实际开发中Code|Message相互匹配
response.setHeader('content-type', 'text/html;charset=utf-8'); //解决中文乱码;
//设置响应体:
response.write('writerOne');
response.write('writerTwo'); //向响应体中写入数据块
response.end('未知路径请求'); //每个请求结束响应,将响应发送给客户端,必须end 则请求未响应;
});最终响应体: 会将write 和 end 的响应内容进行拼接合并,全部响应回客户端
res.write(chunk[, encoding][, callback]) 向响应体中写入数据块res.end([data][, encoding][, callback]) 结束响应过程,将响应发送给客户端,可携带最终的响应数据对于一个web项目,通常分为:前端——后端通过HTTP协议:前端发送请求——后端接受请求响应资源——前端接受响应页面渲染:
请求的类型方式有很多,所以响应的资源也有很多类型:HTML、CSS、JS、图片|视频... 浏览器改如何知道,后端响应的是什么类型呢?
HTTP响应中的资源类型主要通过Content-Type标头字段来指定客户端所接收到的数据是什么类型的
以下常见的HTTP响应资源类型,这是 MIME Multipurpose Internet Mail Extensions 类型:
或选择 application/octet-stream 类型,浏览器会对响应体内容进行独立存储,也就是我们常见的下载效果
/** HTTP 设置响应资源报文 */
const server = http.createServer((request, response) => {
response.setHeader('Content-Type', 'text/html;charset=utf-8'); //并设置资源的编码格式;
response.write(`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Node.js HTTP Server</title>
</head>`
);
response.end(`
<body>
<h1>Hello, Node.js!</h1>
<script>
// 嵌入的 JavaScript 代码
alert('This is JavaScript running on the server!');
</script>
</body>
</html>`
);
});<meta charset="UTF-8"> 😕但 ,Content-Type 设置编码格式优先级更高CSS、JS... 等资源中的编码格式,则会默认根据当前依附的HTML网页 的编码格式而设置;fs 进行读取响应,提高代码可读性;这个地方了解即可,个人总结存在差异,请指出,现在大部分的框架已经实现了这一块的功能,所以实际开发接触不多😬
以下是一个简单的HTML页面:
包含一个"Hello World"的文本,使用CSS设置字体并居中,JavaScript实现点击变色效果的例子:initDemo.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello World Page</title>
<style>
body {
margin: 0;
height: 100vh;
display: flex;
font-size: 120px;
align-items: center;
justify-content: center;
font-family: Arial, sans-serif; /* 设置字体 */ }
#helloText { cursor: pointer; /* 添加光标指示可点击 */ }
</style>
</head>
<body>
<div id="helloText">Hello World!</div>
<script>
// JavaScript代码,点击文本时变色
document.getElementById('helloText').addEventListener('click', function() {
var randomColor = getRandomColor();
this.style.color = randomColor;
});
// 随机创建文本颜色
function getRandomColor() {
var color = '#';
var letters = '0123456789ABCDEF';
for (var i = 0; i < 6; i++) { color += letters[Math.floor(Math.random() * 16)]; }
return color;
}
</script>
</body>
</html>拆分上述:initDemo.HTML

响应页面举例升级: 一个响应报文页面可以由很复杂的文本内容组成,为了方便读取|响应,可以通过FS模块 读取响应
且,一个响应报文页面HTML 由多个资源文件组成:html、css、js、img,通常我们都是 FS 读取HTML文件响应,HTML内部调用资源
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello World Page</title>
<link rel="stylesheet" href="css/styles.css">
</head>
<body>
<div id="helloText">Hello World!</div>
<script src="js/script.js" ></script>
</body>
</html>通过FS模块:
/** 设置HTTP响应报文 */
const fs = require('fs');
const http = require('http');
/** HTTP 设置响应资源报文 */
const server = http.createServer((request, response) => {
response.setHeader('Content-Type', 'text/html;charset=utf-8');
let html = fs.readFileSync(__dirname+'/resource/index.html');
response.end(html);
});
//使用 server服务器对象监听端口,启动服务:
server.listen(5400, () => { console.log('node Server 启动!!'); })这里通过,FS读取 index.html 响应页面,但有一个问题:突然发现页面的 CSS JS 失效了❓
F12 排查——原来,是因为服务器的响应固定了 index.html 虽然有CSS | JS的请求,但固定的响应的也都是html上述响应存在BUG: 实际开发中我们需要根据请求路径而响应对应的文件,而文件中的资源文件也需要正确响应;
新增需求: http://127.0.0.1:5400/index 正确响应页面及样式资源,非法路径则404
/** 设置HTTP响应报文 */
const fs = require('fs');
const http = require('http');
/** HTTP 设置响应资源报文 */
const server = http.createServer((request, response) => {
//获取请求URL 解析来判断响应页面资源;
let { pathname } = new URL(request.url,'http://127.0.0.1');
if(pathname === '/index' ){
let h5 = fs.readFileSync(__dirname+'/resource/index.html');
response.end(h5);
}else if(pathname === '/js/script.js'){
let js = fs.readFileSync(__dirname+'/resource/js/script.js');
response.end(js);
}else if(pathname === '/css/styles.css'){
let css = fs.readFileSync(__dirname+'/resource/css/styles.css');
response.end(css);
}else{ response.statusCode = 404; response.end('<H1> 404 NOT FOUND </H1>'); }
});
//使用 server服务器对象监听端口,启动服务:
server.listen(5400, () => { console.log('node Server 启动!!'); });
浏览器请求——服务器未匹配的路径则:==404 NOT FOUND==
上述的写法虽然可以实现但是实在是太笨了,如果服务器有千百万不同的文件类型,这对开发|服务器效率性能压力太大了! ⬆️server.js 代码升级:
/** 设置HTTP响应报文 */
const fs = require('fs');
const path = require('path');
const http = require('http');
let mimes = {
html: 'text/html',
css: 'text/css',
png: 'image/png',
mp4: 'video/mp4',
gif: 'image/gif',
jpg: 'image/jpeg',
mp3: 'audio/mpeg',
js: 'text/javascript',
json: 'application/json' } //变量: 常见的文件响应类型,目前的浏览器都有自动识别资源类型的功能了
/** HTTP 设置响应资源报文 */
const server = http.createServer((request, response) => {
//获取请求URL 解析来判断响应页面资源 变量: 服务器资源路径
let { pathname } = new URL(request.url,'http://127.0.0.1');
let filePath = __dirname + '/resource'+pathname;
//读取路径文件 fs 异步 API 是否存在,给予异常捕获
fs.readFile(filePath, (err, data) => {
if(err){ //判断错误的代号
response.setHeader('content-type','text/html;charset=utf-8');
switch(err.code){
case 'ENOENT':
response.statusCode = 404;
return response.end('<h1>404 Not Found</h1>');
case 'EPERM':
response.statusCode = 403;
return response.end('<h1>403 Forbidden</h1>');
default:
response.statusCode = 500;
return response.end('<h1>Internal Server Error</h1>'); }
}
let ext = path.extname(filePath).slice(1); //获取文件的后缀名
let type = mimes[ext]; //获取对应的类型
if(type){
if(ext === 'html'){ response.setHeader('content-type', type + ';charset=utf-8');
}else{ response.setHeader('content-type', type); }
}else{
response.setHeader('content-type', 'application/octet-stream'); //没有匹配到
}
//响应文件内容
response.end(data);
});
});
//使用 server服务器对象监听端口,启动服务:
server.listen(5400, () => { console.log('node Server 启动!!'); });实际开发,几乎不会设计到服务器的开发,此处了解即可~~
网页中的 URL 主要分为两大类:相对路径与绝对路径
形式 | 特点 |
|---|---|
| 直接向目标资源发送请求:某个网站的外链 |
//wsm.com/Demo | 与页面 URL 的协议拼接形成完整 URL 再发送请求 |
/web | 与页面 URL 的协议、主机名、端口拼接形成完整 URL 再发送请求 |
例如当前网页 url 为: http://www.wsm.com/course/index.html
形式 | 最终的 URL |
|---|---|
./css/app.css |
|
js/app.js |
|
../img/logo.png |
|
如下Demo案例: HTML文件,通过VsCode+插件Live-Server工具可以快速部署前端页面——==F12 查看浏览器拼接路径资源==
<body>
<!-- 绝对路径 -->
<a href="https://www.baidu.com">百度</a>
<a href="//jd.com">京东</a>
<a href="/search">搜索</a>
<hr>
<!-- 相对路径 -->
<a href="./css/app.css">访问CSS</a>
<a href="js/app.js">访问JS</a>
<a href="../img/logo.png">访问图片</a>
<a href="../../img/logo.png">访问图片</a>
</body>
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。