node.js入门教程

目录

  • node.js
    • 前言
    • node是什么?
    • node的应用?
    • Buffer
    • fs模块
    • path模块
    • HTTP协议
      • 请求报文
      • 响应报文
    • HTTP模块
    • 模块化
      • 如何模块化?
      • 导入的基本流程?
    • 包管理工具
      • npm
      • 初始化
      • 安装
      • 删除
      • 开发环境
      • 配置命令别名

node.js

前言

       这是我第三次对node.js进行学习,第一次是在校的大二下学期,因为自己能力的局限性,在B站看完全部教学视频自己也有使用node.js写api接口,所掌握的知识点十分有限。第二次是大三的寒假对node.js进行了二刷,对知识的理解也比第一次更深刻。这次是笔者大三下学期,此时的我已经在公司里实习了,因为项目中的服务器端使用的就是node.js,leader也分配了一些设计api接口的任务。因此借五一假期进行三刷,同时写下本编文章,记录自己的学习路程。时间真快,最后,祝自己能找到一份理想的工作。
node.js入门教程_第1张图片

       随着时代的发展,前端程序员必备的开发知识也不仅局限于HTMLCSSJavascript前端框架如Vue、React、Angular等了。node.js也成为了一项必备的技能之一,相信接触过招聘网站的同学都知道,十个前端岗位要求中,超过一半是需要具备服务器端开发语言的,其中node.js就属于其中,其必要性可想而知。

node是什么?

​ 以下是对node.js官网的一句原话。翻译过来的意思就是:Node.js是一个开源的,跨平台的JavaScript运行环境。通俗点来说:Node.js就是一款应用程序,是一款软件,它可以运行JavaScript。

Node.js@ is an open-source, cross-platform JavaScript runtime enviroment.
node.js入门教程_第2张图片

node的应用?

  • 开发服务器应用
    • 静态页面访问
  • 开发工具类应用
    • Vite
    • Webpack
    • Babel
  • 开发桌面端应用
    • vsCode
    • postman
    • Figma

node.js入门教程_第3张图片

注意:在node.js中是不能操作DOM和BOM的,因为node.js中的JavaScript组成部分是由ECMAScript组成和Node API组成,JavaScript则是由ECAMScript、Web API组成,要注意区分二者的区别。

小结

  1. Node.js中不能使用BOM和DOM的API,可以使用console和定时器API
  2. Nod.js中的顶级对象为global,也可以使用globalThis访问顶级对象

Buffer

Buffer 中文译为[缓冲区],是一个类似于 Array 的对象,用于表示固定长度的字节序列

换句话说,Buffer 就是一段固定长度的内存空间,用于处理二进制数据

node.js入门教程_第4张图片

创建

buffer的创建有三种方式,分别为alloc、allocUnsafe、from

// 1. alloc
let buf = Buffer.alloc(10);
console.log(buf); // 

// 2.allocUnsafe 可能会包含旧的内存数据,速度相比alloc较快些
let buf2 = Buffer.allocUnsafe(10);
console.log(buf); // 

// 3. from 该方法会将参数转化为对应的Unicode(ASCII)
let buf3 = Buffer.from("hello");
console.log(buf3) // 

转换

Buffer的可阅读性没有那么强,我们可以使用toString()方法的调用来将数据Buffer流转换为字符串,提高可阅读性。

let buf = Buffer.from("hello");

let str = buf.toString(); // hello

修改

在buffer中可以使用访问数据元素的方式进行buffer对应下标的数据访问,如buffer[0]、buffer[1]、buffer[2]…,也可以使用赋值的方式进行修改buffer[0] = 98(Unicode)

let buffer = Buffer.from('hello')
console.log(buffer) // 

// 修改buffer[0]
buffer[0] = 95;
console.log(buffer) // 

溢出

计算机中8个字位的二进制存储只能存储十进制的255,即最大十进制数据就是255,超过后就会溢出。在buffer中,当二进制溢出时会舍弃最高位的数字。举个例子:buffer[0] = 361 361转换位二进制为:0001 0110 1001,因为只能存储八位因此存储的结果为0110 1001。

中文

在buffer中,一个中文占3个字节

let buf = Buffer.from('你好');

console.log(buf); // 

fs模块

file system:fs模块可以实现与硬盘的交互,例如:文件的创建、删除、重命名、移动,还有文件内容的写入、读取,以及文件夹的相关操作。

在node.js中,我们可以使用require的方式将fs模块导入。

写入

方法 说明
writeFile 异步写入
writeFileSync 同步写入
createWriteStream 流式写入

fs模块中有一个writeFile(异步)/ writeFileSync(同步)方法,可以创建文件并写入内容。

/*
* fs.writeFile(File, data[, option],callback)
* @param: file 文件名(必选)
* @param: data 待写入的内容(必须)
* @param: option 选项配置(可选),表示以什么格式方式写入文件,默认值是utf8
* @param:callback 回调函数(必选)
*/
const fs = require('fs')

fs.writeFile('../files/write.txt', '写入内容', (err, data) => {
    if (err) {
        console.log('写入文件失败' + err.message);
        return;
    }
    console.log(data);
    return;
})

文件的写入还有第二种方式就是使用createWriteStream流式写入,程序打开一个文件是需要消耗资源的,流式写入可以减少打开关闭文件的次数。流式写入方式适用于大文件写入或者频繁写入的场景,而writeFilefont适合于写入频繁较低的场景

const fs = require('fs');

const ws = fs.createWriteStream('../files/观书有感.txt');

ws.write('半亩方塘一鉴开\r\n');
ws.write('天光云影共徘徊\r\n');
ws.write('问渠那得清如许\r\n');
ws.write('为有源头活水来\r\n');

ws.close();

文件写入的场景:

  • 下载文件
  • 安装软件
  • 保存程序日志,如Git
  • 编辑器保存文件
  • 视频录制

需要持久化保存数据的时候,应该想到文件写入

追加

fs模块中有一个appendFile(异步) / appendFileSync(同步)方法,可以创建文件并追加内容

/*
* fs.appendFile(File, data[, option],callback)
* @param: file 文件名(必选)
* @param: data 待写入的内容(必须)
* @param: option 选项配置(可选),表示以什么格式方式写入文件,默认值是utf8
* @param:callback 回调函数(必选)
* return: undefined
*/
const fs = require('fs');

fs.appendFile('../files/write.txt', "\r\n我是追加的内容", (err, res) => {
    if (err) {
        return console.log('错误', err.message)
    }
    console.log(res);
    return;
})

读取

方法 说明
readFile 异步读取
readFileSync 同步读取
createReadStream 流式读取

fs模块中有一个readFile(异步)/ readFileSync(同步)方法,可以读取文件内容。

/* 	readFile(path[, option], callback)
*  @param: path(必选) 文件路径
*  @param:option(可选) 读取文件的编码格式
*  @param:callback(必选)回调函数
*  return: undefined
*/
const fs = require('fs')

// 异步读取
fs.readFile('../结项总结.txt', 'utf8', (err, data) => {
    if (err) {
        console.log('读取文件失败!' + err.message);
        return
    }
    console.log('读取文件成功!' + data);
    return
})

// 同步读取
let data = fs.readFileSync('../结项总结.txt');
console.log(data.toString());

// 创建流式读取对象
const rs = fs.createReadStream(path);

// 绑定data事件,chunk
rs.on('data', chunk => {
    
})

// end 可选事件,当数据读取结束后自动执行
rs.on('end', ()=> {
    console.log('读取完成');
})

文件读取的场景:

  • 电脑开机
  • 程序运行
  • 编辑器打开文件
  • 查看图片
  • 播放视频…

移动

在Node.js中,我们可以使用rename或者renameSync来移动或者重命名文件或者文件夹

语法:

fs.rename(oldPath, newPath, callback)

fs.renameSync(oldPath, newPath)

参数说明:

  • oldPath:文件当前的额路径
  • newPath:文件新的路径
  • callback:操作后的回调函数
const fs = require('fs');

// rename方法
fs.rename('../files/观书有感.txt', './观书有感.txt', err => {
    if (err) return console.log(err.message);
    console.log("重命名成功!");
})

// renameSync方法
fs.renameSync('./观书有感.txt', '../files/观书有感.txt');

删除

在Node.js中,我们可以使用unlink或者unlinkSync来删除文件

语法:

fs.unlink(path, callback)

fs.unlinkSync(path)

参数说明:

  • path:文件路径
  • callback:操作后的回调
const fs = require('fs');

// unlink
fs.unlink('../files/test.txt', err => {
    if (err) return console.log(err.message);

    console.log("文件删除成功...");
})

// unlinkSync
fs.unlink('../files/test.txt');

操作文件夹

在node.js中,我们以对文件夹进行以下的操作

方法 说明
mkdir / mkdirSync 创建文件夹
readdir / readdirSync 读取文件夹
rmdir / rmdirSync 删除文件夹

创建

在Node.js中,我们可以使用mkdir或者mkdirSync来创建文件夹

语法:

fs.mkdir(path[, option], callback)

fs.mkdirSync(path[, option])

参数说明:

  • path:文件夹路径
  • option:选项配置(可选)
  • callback:操作后的回调

**其中:**当我们需要将path进行递归生成子目录时,可以在option中添加{recursive:true}

读取

在Node.js中,我们可以使用mkdir或者mkdirSync来创建文件夹

语法:

fs.readdir(path[, option], callback)

fs.readdirSync(path[, option])

参数说明:

  • path:文件夹路径
  • option:选项配置(可选)
  • callback:操作后的回调

删除

在Node.js中,我们可以使用mkdir或者mkdirSync来创建文件夹

语法:

fs.rmdir(path[, option], callback)

fs.rmdirSync(path[, option])

参数说明:

  • path:文件夹路径
  • option:选项配置(可选)
  • callback:操作后的回调

**其中:**当我们需要将path进行递归删除子目录时,可以在option中添加{recursive:true},但是node环境会提示使用fs.rm()

path模块

path模块提供了操作路径的功能,我们将介绍如下几个较为常用的几个API:

API 说明
path.resolve 拼接规范的绝对路径
path.sep 获取操作系统的路径分隔符
path.parse 解析路径并返回对象
path.basename 获取路径的基础名称
path.dirname 获取路径的目录名
path.extname 获取路径的扩展名

HTTP协议

node.js入门教程_第5张图片

请求报文

请求报文由三部分组成,分别是请求行、请求头、请求体

node.js入门教程_第6张图片

请求行

请求行主要由三部分组成请求方式、请求地址(url)、HTTP版本号。
在这里插入图片描述

请求方法:

方法 作用
GET 主要用于获取数据
POST 主要用于新增数据
PUT / PATCH 主要用于更新数据
DELETE 主要用于删除数据
HEAD / OPTIONS / CONNECT / TRACE 使用相对较少

url(Uniform Resource Locator):统一资源定位符,本身也是一个字符串。

在这里插入图片描述

HTTP版本

版本号 发布时间
1.0 1996年
1.1 1999年
2 2015年
3 2018年

请求头

请求头都是以键值对的形式出现的,记录了浏览器的一些相关信息。

请求体

请求体的内容由开发者决定,多个请求内容由&连接。

响应报文

响应报文主要由三部分组成:响应行、响应头、响应体。我们可以观察到请求报文响应报文的组成结构都是大同小异的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qlDUropy-1682844650973)(E:\node图片\响应报文.png)]

响应行:主要由HTTP版本号、响应状态码、状态码含义组成。

以下是比较常见的响应状态码和状态码含义:
node.js入门教程_第7张图片
node.js入门教程_第8张图片### IP地址

IP本质上是一个32bit二进制字符串,将每8bit进行拆分,得到IPV4的形式的十进制字符串,同时使用.进行分割,这样就形成了日常我们所接触到的ip形式。
node.js入门教程_第9张图片

HTTP模块

在Node.js中,可以使用引入http模块的方式来创建一个本地服务器。

注意:

  • 在使用http模块时,响应体需要返回中文,但没有设置对应的header时,浏览器收到的数据会乱码

创建

// 1.导入http模块
const http = require('http');
const path = require("path")

// 2.调用createServer,创建http实例
const server = http.createServer((request, response) => {
    // request:请求报文 、 response:响应报文
});

// 3.使用on方法为http实例绑定request事件
server.on('request', (req, res) => {
    res.setHeader('Content-Type', 'text/html;charset=utf-8')
    let url = req.url
    switch (url) {
        case '/api': res.end(JSON.stringify({
            method: req.method,
            msg: "请求成功",
            status: 200,
        }))
            break;

        default:
            res.end("404")  
            break;
    }
    // 3.1 设置响应头,解决中文乱码问题
    res.setHeader('Content-Type', 'text/html;charset=utf-8');
})

// 4.开启服务器
server.listen(8080, () => {
    console.log("serve running");
})

获取请求头

想要获取请求的数据,需要通过request对象。

含义 语法 重点掌握
请求方法 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”, chunk => {})
request.on(“end”, ()=>{})

注意事项:

  1. request.url只能获取路径以及查询字符串,无法获取URL中的域名以及协议的内容
  2. request.headers将请求信息转化为一个对象,并将对象的属性名都转化为了[小写]
  3. 关于路径:如果访问网站的时候,只填写了IP地址或者域名信息,此时请求的路径为[/]
  4. 关于favicon.ico:这个请求是属于浏览器自动发送的请求

DEMO

const http = require('http');
const server = http.createServer();

server.on('request', (req, res) => {
    let { method } = req;
    let { pathname } = new URL(req.url, "http://127.0.0.1:8000");

    res.setHeader("Content-Type", "text/html;charset=utf-8");

    if (method === 'POST' && pathname === '/login') {
        return res.end("登录页面")
    } else if (method === 'POST' && pathname === '/register') {
        return res.end("注册页面")
    };

    return res.end('404 not found');
})

server.listen(8000, () => {
    console.log("8000端口监听...");
})

设置响应报文

我们可以通过回调函数中callback的response参数设置响应报文。

  1. 设置响应状态码:response.statusCode = 具体数值

  2. 设置响应状态码描述内容:response.statusMessage = 字符串(不能为中文)

  3. 设置响应头:response.setHeaders(‘key’, ‘value’)

  4. 设置响应体:response.write() / response.end(),前者可以调用多次,后者只能调用一次

mime类型

媒体类型(通常称为Multipurpose Internet Mail Extensions 或者 MIME类型)是一种标准,用来表示文档、文件或者字节流的性质和格式

mime类型结构: [type] / [subType]

例如:text / html text / csss image / jpeg image / png application / json

HTTP服务可以设置响应头Content-Type来明确响应体的MIME类型,浏览器会根据类型决定如何处理资源

下面是常见文件对应的minme类型

html:’text/html‘,

css:’text/css‘,

js:’text/javascript‘

对于未知的资源类型,可以选择application/octet-stream类型,浏览器在遇到该类型的响应时,会对响应体内容进行独立存储,也就是我们常见的下载效果。

Get和POST请求

GET请求的情况:

  • 在地址栏直接输入url访问
  • 点击a链接
  • link标签引入css
  • script标签引入js
  • video与audio要引入多媒体
  • img标签引入图片
  • form标签的中的method为GET(不区分大小写)
  • ajax中的GET请求

POST请求的情况:

  • form标签中的method为POST(不区分大小写)
  • AJAX的POST请求

GET和POST请求的区别

GET和POST是HTTP协议请求的两种方式,主要有如下几个区别

  1. 作用。GET主要用于获取数据,POST主要用于提交数据
  2. 参数位置。GET带参数请求是将参数缀到URL之后,POST带参数请求时将参数放到请求体中
  3. 安全性。POST请求相对GET安全一些,因为在浏览器中参数会暴露在地址栏
  4. GET请求大小有限制,一般为2k,而POST请求则没有限制

模块化

什么是模块化与模块 ?

将一个复杂的程序文件依据一定规则(规范)拆分成多个文件的过程称之为 模块化

其中拆分出的 每个文件就是一个模块 ,模块的内部数据是私有的,不过模块可以暴露内部数据以便其他模块使用

什么是模块化项目 ?

编码时是按照模块一个一个编码的,整个项目就是一个模块化的项目

模块化好处

  1. 防止命名冲突
  2. 高复用性
  3. 高维护性

如何模块化?

在Node.js中,遵循的是CommonJS规范。可以使用exportsmodule.exports的将变量或者函数暴露的方式实现模块化。相同的,如果某个文件需要用到模块化中的数据时,可以使用require的方式将所需要的数据进行引入。

模块暴露数据的方式有两种:

  1. module.exports = value

  2. exports.name = value

使用时有几点注意:

  • module.exports可以暴露任意数据
  • 不能使用 exports = value 的形式暴露数据,模块内部module 与 exports 的隐式关系 exports =module .exports ={}
  • require返回的结果是module.exports中的值

node.js入门教程_第10张图片

// 01.m1.js文件如下
console.log('加载了01.m1.js');
const name = 'eason';

exports = name; // 这种暴露的方法是错误的

module.exports = { name };
// 02.m2.js文件
const m1 = require('./01.m1') // 注意加载可以省略后缀名
console.log(m1.name); // 输入eason

在模块中使用 require 传入文件路径即可引入文件

const test = require('./me.js');

require 使用的一些注意事项

  1. 对于自己创建的模块,导入时路径建议写相对路径 ,且不能省略 ./ …/

  2. js json 文件导入时可以不用写后缀,c/c++编写的 node 扩展文件也可以不写后缀,但是一般用不到

  3. 如果导入其他类型的文件,会以 js 文件进行处理

  4. 如果导入的路径是个文件夹,则会首先检测该文件夹下 package.json 文件中 main 属性对应的文件如果 main 属性不存在,或者 package.json 不存在,则会检测文件夹下的 index.jsindex.json如果还是没找到,就会报错

  5. 导入 node.js 内置模块时,直接 require 模块的名字即可,无需加 ./和…

    1. require 还有一种使用场景,会在 包管理工具 节介绍

    2. module.exportsexports 以及 require 这些都是 CommonJS 模块化规范中的内容而 Node.js 实现了 CommonJS 模块化规范

导入的基本流程?

介绍一下require导入的自定义模块的基本流程

  1. 将相对路径转为绝对路径,定位目标文件
  2. 缓存检测
  3. 读取目标代码
  4. 包裹一个函数并执行(自执行函数)。通过arguments.callee.toString()查看执行函数
  5. 缓存模块的值
  6. 返回module.exports的值

包管理工具

  1. 包是什么?

[包] 英文单词是 package,代表了一组特定功能的源码集合

  1. 包管理工具

管理[包]的应用软件,可以对[包] 进行 下载安装 , 更新, 删除 , 上传 等操作

借助包管理工具,可以快速开发项目,提升开发效率

包管理工具是一个通用的概念,很多编程语言都有包管理工具,所以 掌握好包管理工具非常重要

  1. 常用的包管理工具

下面列举了前端常用的包管理工具

  • npm
  • yarn
  • cnpm

npm

npm 全称 Node Package Manager ,翻译为中文意思是 [Node 的包管理工具Jnpm 是 node.js 官方内置

包管理工具,是必须要掌握住的工具

  1. npm 的安装

node.js 在安装时会自动安装 npm ,所以如果你已经安装了 node.js,可以直接使用 npm可以通过 npm -v

查看版本号测试,如果显示版本号说明安装成功,反之安装失败
node.js入门教程_第11张图片

查看版本时可能与上图版本号不一样,不过不影响正常使用

初始化

npm init 

npm init 命令的作用是将文件夹初始化为一个[包],交互式创建 package.json 文件

package.json 是包的配置文件,每个包都必须要有 package.json

{
    "name":1-npm” #包的名字
	"version":"1.0.0" #包的版本
    "description": "" #包的描述
    "main":"index.js", #包的入口文件
    "scripts":{    #脚本配置
    	"test":"echo \"Error: no test specified\" && exit 1"
    }
    "author": #作者
	"license":"ISC" #开源证书
}

初始化的过程中还有一些注意事项

  1. package name(包名)不能使用中文、大写,默认值是 文件夹的名称,所以文件夹名称也不能使用中文和大写
  2. version(版本号)要求 x.x.x 的形式定义,x 必须是数字,默认值是 1.0.0
  3. ISC证书与 MIT 证书功能上是相同的,关于开源证书扩展阅读
  4. package.json 可以手动创建与修改
  5. 使用 npm init -y 或者 npm init --yes 极速创建 package.json

安装

我们可以通过 npm install npm i 命令安装包,其中使用npm i <包名>@指定版本可以实现安装指定版本的依赖包。同时 npm i -g <包名>@指定版本 npm i在i 后添加 -g的命令可以实现全局安装,此时安装的依赖包会被安装到本地计算机中。**注意:**window系统下默认是不允许安装全局脚本的,因此需要使用管理员身份运行命令行窗口,执行该行命令set-ExecutionPolicy remoteSigned,选Y即可。可以使用npm i <包名> <包名> <包名>…一次性安装多个依赖包。

npm install <包名>
npm i <包名>

npm i <包名>@指定版本  # 安装指定版本包
npm i -g <包名>@指定版本 # 全局安装包
npm i <包名> <包名> <包名>... #安装多个依赖包

示例

npm install uniq
npm i unig

运行之后文件夹下会增加两个资源

  • node_modules 文件夹 存放下载的包

  • package-lock.ison 包的锁文件 ,用来锁定包的版本

    安装 unig 之后,unig 就是当前这个包的一个依赖包,有时会简称为 依赖比如我们创建一个包名字为A,A中安装了包名字是 B,我们就说 B 是 A 的一个依赖包,也会说 A 依赖 B

删除

在npm中使用npm uninstall <包名>即可将依赖包进行删除

npm uninstall <包名>

开发环境

开发环境是程序员 专门用来写代码 的环境,一般是指程序员的电脑,开发环境的项目一般 只能程序员自己

访问

生产环境是项目 代码正式运行 的环境,一般是指正式的服务器电脑,生产环境的项目一般 每个客户都可以访问

生产依赖与开发依赖
我们可以在安装时设置选项来区分 依赖的类型,目前分为两类

类型 命令 补充
生产依赖 npm i -S unig
npm i --save uniq
-S等效于 --save,-S是默认选项
包信息保存在 package.json 中 dependencies 属性
开发依赖 npm i -D less
npmi–save-devrless
-D等效于 --save-dev
包信息保存在package.json 中 devDependencies 属性

配置命令别名

通过配置命令别名可以更简单的执行命令

配置 package.json中的 scripts 属性

{
	'scripts":{
		"server":"node server .js"
		"start":"node index.js",
	}
}

配置完成之后,可以使用别名执行命令

npm run server
npm run start

不过 start 别名比较特别,使用时可以省略 run

npm start

补充说明:

  • npm start 是项目中常用的一个命令,一般用来启动项目.

  • npm run 有自动向上级目录查找的特性,跟 require 函数也一样

  • 对于陌生的项目,我们可以通过查看 scrIpts 属性来参考项目的一些操作

你可能感兴趣的:(node.js,前端,服务器)