一波Node.js总结 【Sort-Plan】

·  阅读 373

截屏2022-05-10 下午3.20.59.png

前段时间看的b站的免费Node视频做的一些笔记,今天抽空整理了一下,有里面老师课程的东西,也有自己之后查的一些资料或者图片。相当于再做一次总结吧。总体的内容可以看上面的导图。

1. 初识node.js

1.1. 浏览器中的javascript的组成部分

1.1.1 js核心语法、

在学习node之前,首先我们要去了解一下javascript的基础知识,比如需要看下《javascript高级程序设计》,es6或者其他一些js基础的书,博客,视频等。

  • 变量,数据类型
  • 循环,分钟,判断
  • 函数,作用域 this
  • 原型链,异步 es6 。。。

1.1.2 webapi

  • DOM操作
  • BOM操作
  • 基于xmlhttprequest 的ajax操作 。。。

1.2. 为什么javascript可以在浏览器中执行呢?

在浏览器中,当有待执行的javascript代码,会调用javascript解析引擎,不同的浏览器采用的是不同的javascript解析引擎

  • chrome 浏览器 - v8
  • Firefox浏览器 - OdinMonkey
  • safri 浏览器 - JSCore
  • IE 浏览器 - Chakra

Chrome浏览器的V8引擎性能最好

1.3. 为什么javascript可以操作浏览器的BOM和DOM?

浏览器中内置了很多api,比如DOMApi BOMApi AjaxApi

开发者可以使用javascript代码代码调用这些webapi,然后这些待执行代码就会调用javasciprt解析引擎。

1.4. 浏览器中的javascript运行环境

运行环境是指代码政策运行所需要的环境

Chrome浏览器运行环境如果需要正常执行js:

  • v8引擎
  • 内置Api:DOM BOM Ajax api

内置api是由运行环境提供的特殊接口,只能在所属的运行环境中被调用

2. node简介

2.1 什么是node.js

node.js是一个基于Chrome V8引擎的javascript运行环境

2.2 node.js中的javascript运行环境

node.js运行环境

  • V8 引擎
  • 内置API:fs path http js内置对象 querystring 等等。。
  1. 浏览器是js的前端运行环境
  2. node.js是js的后端运行环境
  3. node.js中无法操作DOM,BOM等浏览器内置API

2.3 node.js可以做什么

node.js作为一个js的运行环境,仅仅提供了基础的功能和api,然而,基于node.js提供的这些基础,很多强大的工具和框架层出不穷:

2.4 node.js怎么学?

  • javascript基础语法
  • node内置API模块(fs,path,http等)
  • express mysql

3.fs文件系统模块

3.1 什么是fs文件系统模块

fs模块是node.js官方提供的,用来操作文件的模块,它提供了一系列的方法和属性,用来满足用户对文件的操作需求

fs.readFile(): 用来读取指定文件中的内容 fs.writeFile(): 用来写入指定文件中的内容

const fs = require('fs');
复制代码

3.2 读取指定文件中的内容

fs.readFile(path[,options],callback)
复制代码
  • path:字符串,表示文件的路径
  • options:表示以哪种编码格式来读取文件
  • callback:文件读取完后,通过毁掉函数拿到读取的结果

以utf8的编码格式,读取制定文件中的内容,并且打印err和dataStr的值

const fs = require('fs');
fs.readFile('./text.txt','utf8',function(err,dataStr) {
    console.log(err); // 执行成功为null
    console.log('...');
    console.log(dataStr);
})
// null
// ...
// hhh
复制代码

3.3 写入指定文件中的内容

fs.writeFile(file,data[,options],callback);
复制代码
  • file:字符串,表示文件的路径
  • data: 表示需要写入的内容
  • options:表示以哪种编码格式来读取文件
  • callback:文件读取完后,通过毁掉函数拿到读取的结果
const fs = require('fs');

fs.writeFile('./2.txt','kk','utf-8',function(err,dataStr) {
    console.log(err); // 文件写入成功为null
    // 写入失败,返回错误对象
    console.log(dataStr);
})
复制代码

4. 考试成绩整理

哈哈=4 哈哈哈哈=7 网盘=9 经济=10
复制代码
哈哈: 4
哈哈哈哈: 7
网盘: 9
经济: 10
复制代码
const fs = require('fs');
fs.readFile('./成绩.txt','utf-8',function(err,dataStr) {
    console.log(dataStr);
    if (err) {
        return console.log('读取文件失败')
    }
    const arrOld = dataStr.split(' ');

    const arrNew = [];

    arrOld.forEach(item => {
        arrNew.push(item.replace('=',': '));
    })

    const newStr =  arrNew.join('\r\n');

    fs.writeFile('./成绩-ok.txt',newStr,'utf-8',function(err,dataStr) {
        console.log(err);
        if (err) {
            return console.log('写入失败');
        }
    })
})


复制代码

5. 动态路径

在使用fs模块操作文件的时候,如果提供的操作路径是./ ../开通的相对路径时,很容易出现路径动态拼接错误的问题,原因:代码在运行的时候,会以执行node命令时所处的目录,动态拼接出被操作文件的完整路径。

fs.readFileSync('./1.md','utf-8',function(err,dataStr) {
    if (err) {
        return console.log('错误了');
    }
})
复制代码

比如有个文件b-node 里面有1.js和1.md,现在在1.js里面写node代码读取1.md的内容,执行node 1.js

  • /Users/wangpangzi/Desktop/node-record/b-node node 1.js

  • /Users/wangpangzi/Desktop/node-record/b-node/1.md

  • /Users/wangpangzi/Desktop/node-record node 1.js

  • /Users/wangpangzi/Desktop/node-record/1.md (找不到,报错)

需要在对应的目录下执行node命令。

如何解决这个问题:使用绝对路径 __dirname 表示当前文件目录

6. path 路径模块

6.1 什么是path路径模块

path路径模块手node.js提供的,用来处理路径的模块,它提供了一系列的方法和属性,用来满足用户对路径的处理需求。

例如:

  • path.join():用来将多个路径片段拼接成一个完整的路径字符串。
  • path.basename():用来从路径字符串中,将文件名解析出来。

如果要在javascript代码中,使用path模块来处理路径,需要先导入:

const path = require('path');
复制代码

6.2 路径拼接

1. path.join()的语法格式

path.join([...paths]);
复制代码
  • ...paths 路径片段的序列
  • 返回值:string
const path = require('path');

const pathstr = path.join('/a','/b/c','../','./d','e');
// ../ 有抵消路径的效果,注意下
// ./ 不会抵消
console.log(pathstr)

const pathstr2 = path.join(__dirname,'./a');
console.log(pathstr2);

// /a/b/d/e
// /Users/wangpangzi/Desktop/node-record/b-node/4-14/a
复制代码

凡是涉及到路径拼接的操作,都使用path.join(),不用+进行字符串的拼接。

2. path.basename()的语法格式

path.baseename(path[,ext]);
复制代码
  • path 表示一个路径的字符串
  • ext 表示文件的扩展名
  • 返回值 表示路径中的最后一部分
const path = require('path');

const fpath = '/a/b/c/index.html';//文件存在的路径

var fullName = path.basename(fpath);
console.log(fullName);
// index.html


var fullName1 = path.basename(fpath,'.html');
console.log(fullName1);
// index
复制代码

3. path.extname()的语法格式

使用path.extname()方法,可以获取路径中的扩展名部分

path.extname(path);
复制代码
  • path 表示一个路径的字符串
  • 返回值 返回得到的扩展名字符串
const path = require('path');

const fpath = '/a/b/c/index.html';//路径字符串

const fext = path.extname(fpath);
console.log(fext); // .html
复制代码

7. http 模块

7.1 什么的客户端和服务器端

在网络节点中,负责消费资源的电脑,叫做客户端;负责对外提供网络资源的电脑,叫做服务器。

http模块是node.js官方提供的,用来创建web服务器的模块,通过http模块提供的http.createServer()方法,就可以方便的把一台普通的电脑,变成一台web服务器,从而对外提供web资源服务。

使用http模块,首先进行导入:

const http = require('http');
复制代码

7.2 进一步理解http模块作用

服务器和普通电脑的区别在于,服务器上安装了web服务器软件,通过安装这些服务器软件,就可以把一台普通的电脑变成一台web服务器。

7.3 服务器相关的概念

IP地址: 互联网上每台计算机的唯一地址 域名和域名服务器: 端口号:

7.4 创建最基础的web服务器

  • 导入http模块
const http = require('http');
复制代码
  • 创建web服务器实例 调用http.createServer()方法,可以快速的创建一个web服务器
const server = http.createServer();
复制代码
  • 为服务器实例榜单request事件,监听客户端的请求
sever.on('request',(req,res) => {
    // 只要有客户端来请求服务器,就会触发request事件,从而调用这个事件处理函数
    console.log('成功');
})
复制代码
  • 启动服务器 调用服务器实例的.listen()方法,可以启动当前的微博服务器实例。
server.listen(80,() => {
    console.log('启动');
});
复制代码

1. req请求对象 res响应对象

只要服务器接受到了客户端的请求,就会调用通过server.on为服务器榜单的request事件处理函数。

如果想在事件处理函数中,访问与客户端相关的数据和熟悉,可以使用如下方式:

server.on('request',(req,res) => {
    // url 地址
    // method GET
    const str = `jing ${req.url} and ${req.method}`; // jing / and GET
    console.log(str);
    res.end(str);
})
复制代码

2. 解决中文乱码的问题

server.on('request',(req,res) => {
    const str = `哈哈哈哈 ${req.url} and ${req.method}`; // jing / and GET
    console.log(str);
    res.setHeader('Content-Type','text/html; charset=utf-8')
    res.end(str);
})
复制代码

3. 根据不同的请求返回不同的响应结果

  • 获取请求的url地址
  • 设置默认的响应内容为404 not found
  • 判断用户请求的是否为/ 或者/index.html首页
  • 判断用户请求的是否为/about.html关于页面
  • 设置Content-Type 相应头,防止中文乱码
  • res.end()把内容响应给客户端

动态响应内容

server.on('request',(req,res) => {
    const url = req.url;
    let content = '<div>404</div>';
    if (url === '/' || url === '/index.html') {
        content = '<h1>首页</h1>'
    } else if(url === '/about.html') {
        content = '<h1>关于</h1>'
    }

    res.setHeader('Content-Type','text/html; charset=utf-8');
    res.end(content);
})
复制代码

8. 模块化

  • 模块化的好处
  • CommonJs规定了哪些内容
  • nodeJs中模块的三大分类
  • npm管理包
  • 规范包结构
  • 模块的加载机制

8.1 编程里面的模块化

遵守一定的规则,把一个大恩家拆分成独立并且互相依赖的多个小模块

把代码进行模块化划分的好处:

  • 提高了代码的复用性
  • 提高了代码的可维护性
  • 可以实现按需加载

8.2 模块化规范

对代码进行模块化的拆分和组合时,需要遵循的规则

  • 使用规范来引入和导出模块

8.3 node中模块的分类

  • 内置·模块 http fs http
  • 自定义模块:用户创建的模块
  • 第三方模块(需要下载使用)

8.4 加载模块

使用require方法进行加载

const fs = require('fs');

const custom = require('./custom.js');

const monent = require('moment');
复制代码

使用require方法加载其他模块的时候,会窒息被加载模块中的代码;可以省略扩展名

8.5 模块作用域

3.js

const jing = 'jing';

function foo() {
    console.log(jing);
}
复制代码

4.js访问不到3.js中的数据,防止全局污染

const cutom = require('./3.js');

console.log(cutom);
复制代码

8.6 向外共享模块作用域中的成员

1. module对象

在.js自定义模块中都有一个module对象,它里面存储了和当前模块有关的信息,

id: '.',
  path: '/Users/wangpangzi/Desktop/node-record/b-node/4-20', //当前模块存储路径
  exports: {}, // 可以向外共享成员
  filename: '/Users/wangpangzi/Desktop/node-record/b-node/4-20/4.js',
  loaded: false,
  children: [
    Module {
      id: '/Users/wangpangzi/Desktop/node-record/b-node/4-20/3.js',
      path: '/Users/wangpangzi/Desktop/node-record/b-node/4-20',
      exports: {},
      filename: '/Users/wangpangzi/Desktop/node-record/b-node/4-20/3.js',
      loaded: true,
      children: [],
      paths: [Array]
    }
  ],
  paths: [...]
复制代码

9. node中的模块化

9.1 向外共享模块作用域中的成员

  1. mmodule.exports对象

在自定义模块中,可以使用module.exports对象,将模块内的成员共享出去,供外界使用。

外界使用require方法导入自定义模块时,得到的就是module.exports所指向的对象

当2中没有东西

const m = require('./2');

console.log(m); // {}
复制代码

当文件2中写入以下内容: 将会打印{ username: 'zhangsan', sayhello: [Function (anonymous)], age: 24 }

// 在一个自定义模块中,默认情况下,module.exports = {};

const age = 24;

// 向module.exports对象上挂载username属性
module.exports.username = 'zhangsan';

module.exports.sayhello = function() {
    console.log('hello');
}

module.exports.age = age;
复制代码

9.2 共享成员时的注意点

使用require方法导入模块的时候,导入的结果,永远以module.exports指向的对象为准

3文件

const n = require('./4');

console.log(n);
复制代码

4文件

module.exports.username = 'zhangsan'; //module.exports上挂载username

module.exports.sayhello = function() {  //module.exports上挂载函数sayhello
    console.log('hello');
}


// module.exports指向全新的对象
module.exports = {
    name: 'jing',
    sayhi() {
        console.log('0')
    }
}
复制代码

对象属性赋值,和对象赋值

9.3 exports 对象

由于module.exports单词写起来麻烦,为了简化向外共享成员的代码,node提供了提供了exports对象,默认情况下,exports和module.exports指向的是同一个对象,最终结果,以module.exports为准。

const username = 'lj';

module.exports.username = username;
exports.age = 30;
exports.foo = function() {
    console.log('hhh');
}
复制代码
{ username: 'lj', age: 30, foo: [Function (anonymous)] }
复制代码

9.4 exports和module.exports的使用误区

时刻谨记,require模块的时候,得到的永远是module.exports指向的对象

  • 注意1
exports.usename = 'jing';

module.exports = {
    gerden:'nna',
    age:33
}
复制代码
{ gerden: 'nna', age: 33 }
复制代码
  • 注意2
module.exports.usename = 'jing';

exports = {
    gerden:'nna',
    age:33
}
复制代码
{ usename: 'jing' }
复制代码
  • 注意3
exports.usename = 'jing';

module.exports.age = 33;
复制代码
{ usename: 'jing', age: 33 }
复制代码
  • 注意4
exports = {
    usename:'jing',
    age:90
}

module.exports = exports;
module.exports.gender = 'nam';
复制代码
{ usename: 'jing', age: 90, gender: 'nam' }
复制代码

9.5 CommonJs 模块化规范

node.js 遵循了CommonJs的规范,CommonJs规定了模块的特性和各模块之间如何相互依赖

CommonJs规定:

  1. 每个模块内部,module变量代表当前模块
  2. module变量是一个对象,它的exports属性是对外的接口
  3. 加载某个模块,其实是价值该模块的module.exports熟悉,require方法用于加载模块

10. web开发模式

目前主流的web开发模式有两种

  • 基于服务器端渲染的传统web开发模式
  • 基于前后端分离的新型web开发模式

10.1服务器端渲染的web开发模式

服务器端渲染:服务器发送给客户端的html页面,是在服务器通过字符串的拼接,动态生成的。因此,客户端不需要用ajax这样的技术额外请求页面的数据

app.get('/index.html',(req,res) => {
    // 1.要渲染的数据
    const user = {name:'zs',age:20}
    // 2. 服务器端通过字符串的拼接,动态生成html内容
    const html = `<h1>姓名:${user.name},年龄: ${user.age}</h1>`;
    // 3.把生成好的页面内容响应给客户端,因此,客户端拿到的好似带有真实数据的html,页面
    res.send(html);
})
复制代码

10.2 服务器端渲染的优缺点

优点

  • 前端耗时少:因为服务器端负责动态生成html内容,浏览器只需要直接渲染页面就可以。尤其是移动端
  • 有利于SEO: 因为服务器端响应的是完整的html页面内容,所以爬虫更容易爬取获得信息,更有利于SEO

缺点

  • 占用服务器端资源:服务器端完成html页面内容的拼接,如果请求较多,会对服务器端造成一定的压力
  • 不利于前后端分离,开发效率低:使用服务器端渲染,则无法进行分工合作,尤其对于前端复杂高的项目,不利于项目高效开发

10.3 前后端分离开发

前后端分离:前后端分离的开发模式:依赖于ajax技术的广泛应用,简而言之,前后端分离的web开发模式,就是后端只负责提供api接口,前端使用ajax调用接口的开发模式。

优点

  • 开发体验好:前端专注于ui页面的开发,后段专注于api的开发,且前端有更多的选择性
  • 用户体验好:ajax技术的广泛应用,极大的提高了用户的体验,可以轻松的实现页面的局部刷新。
  • 减轻了服务器端的渲染压力,因为页面最终是在每个用于的浏览器中生成的。

缺点

  • 不利于SEO(搜索引擎优化),因为完整的html页面需要在客户端动态拼接下完成,所以爬虫对无法爬取页面的有效信息。 (解决方案,利于vue,react等前端框架SSR:服务器端渲染技术,能够很好的倔强SEO问题)

10.4 前后端身份认证

通过一定的手段,完成对用户身份的确认

在web开发中,涉及用户的身份认证:手机验证码登陆,邮箱密码登陆,二维码登陆

10.5 不同开发模式下的身份认证

对应服务器端渲染和前后端分离这两种开发模式来说,分别有着不同的身份认证方案:

  • 服务器端渲染推荐使用session认证机制
  • 前后端分离推荐使用Jwt认证机制

1. session认证机制

基于http协议的无状态性

了解http协议的无状态是进一步学习session认证机制的必要前提。

http协议的无状态性,指的是客户端的每次http请求都是独立的,连续多个请求之间没有直接的关系,服务器不会主动保留每次http请求的状态

如何突破http无状态的限制

cookie

2. 什么是cookie

cookie是存储在客户端浏览器中的一段不超过4kb的字符串,它由一个名称,一个值和其他几个用于控制cookie有效期,安全性,用于范围的可选属性性组成

不同域名下的cookie各种独立,每当客户端发起请求时,会自动把当前域名下所有未过期(expires)的cookie一起发送到服务器

  • 自动发送(发请求时)
  • 域名独立
  • 过期时限
  • 4kb限制

3. cookie 在身份证中的作用

  • 客户端第一次请求服务器的时候,服务器通过响应头的形式,向客户端发送一个身份认证的cookie,客户端会自动将cookie保存在浏览器中

  • 当客户端再次请求服务器端数据的时候,浏览器会自动将身份认证相关的cookie,通过请求头的形式发给服务器端,服务器即可验明客户端的身份

4. cookie不具有安全性

cookie是存储在浏览器中的,而且浏览器也提供了读写cookie的api,因此cookie很容易被伪造,不具有安全性,因此不建议服务器将重要的隐私数据,通过cookie的形式发送给浏览器。

cookie+session认证(服务器端认证)

5. session 工作原理

  1. 客户端-服务器端: 客户端登陆:提交账号和密码,服务器端严重账号和密码,将登陆成功后的用户信息存储在服务器的内存,同时生产对应的cookie字符串
  2. 服务器端-客户端: 服务器端响应:将生产的cookie响应给客户端,浏览器端自动把cookie存储在当前域名下
  3. 客户端-服务器端: 当客户端下一次进行请求的时候,通过请求头自动把当前域名下未过期的可用的cookie发生给服务器。
  4. 服务器根据请求头的cookie从内存中对应的用户信息,当前用户信息认证成功后,服务器端针对当前用户生成特定的响应内容。
  5. 服务器端-客户端:把当前用户对应的页面内容响应给浏览器。

10.6 express 中使用session认证

  1. 配置express-session中间件安装成功后,需要通过app.use()来注册session中间件,示例代码如下:
var session = require('express-session');

app.use(session({
    secret: 'keyboard cat',
    resave: false,
    saveUninitialized: true
}))
复制代码
const express = require('express');
const app = express();
// 配置session中间件
const session = require('express-session');
app.use(
    session(
        {
            secret: 'jing',
            resave: false,
            saveUninitialized: true,
        }
    )
)
app.use(express.static('./pages'));
app.use(express.urlencoded({extended: false }));
复制代码

10.7 向session中存取数据,以及销毁

当express-session中间件配置成功后,可以通过req.session来访问和使用session对象,从而存储用户的关键信息。

// 登陆api接口

app.post('/api/login',(req,res) => {
    //判断用户提交的登陆信息是否正确
    if (req.body.username !== admin || req.body.password !== '0000') {
        return res.send({status: 1,msg:'登陆失败'})
    }
    //只有成功配置了express-session这个中间件之后,才能呗访问到

    // 将登陆成功后的用户信息,保存到session中

    req.session.user = req.body; // 用户的信息
    req.session.islogin = true; // 用户的登陆状态

    res.send({status:0,msg:'登陆成功'})
})

// 从session中取数据

app.get('/api/username',(req,res) => {
    // 判断用户是否登陆

    if(!req.session.islogin) {
        return res.send({status:1,msg:'jing'})
    }

    res.send({status:0,msg:'success',username:req.session.user.username})
})

// 退出登陆的接口

app.post('/api/logout',(req,res) => {
    //清空当前客户端对应的session信息
    req.session.destroy()
    res.send({
        status: 0,
        msg: '退出登陆成功'
    })
})
复制代码

10.8 JWT认证机制

  1. 了解session认证的局限性

session认证机制需要配合cookie才能实现,由于cookie默认不支持跨域访问,所以,当涉及到钱的跨域请求后端接口的时候,需要做很多额外的处理,才能实现跨域session认证

注意:

  • 当前端请求后端接口不存在跨域问题的时候,推荐使用session身份认证机制
  • 前端需要跨域请求后段接口的时候,不推荐使用session身份认证机制,推荐使用JWT认证机制

1. 什么是JWT

JWT:是目前最流行的跨域认证解决方案

  1. 客户端登陆提交账号和密码给服务器端
  2. 服务器端验证账号和密码,验证通过后,将用户的信息对象,经过加密之后生产token字符串
  3. 服务器端想要:将生成的token发送给客户端
  4. 客户端将接收到的token存储到localstorage或者sessionstorage
  5. 客户端再次发起请求时,通过请求头的Authorization字段,将token发送给服务器
  6. 服务器端将token字符串还原成用户的信息对象
  7. 用户的身份认证成功后,服务器针对当前用户生成特定的响应内容
  8. 服务器端响应,把当前用户对应的页面内容响应给客户端

用户的信息通过token字符串的形式,保存在客户端浏览器中,服务器端通过还原token字符串的形式来认证用户身份

2.JWT字符串的组成部分

  • header:头部

  • payload: 有效荷载 这个部分是真正的用户信息,它是用户信息经过加密后生成的字符串

  • signature: 签名

比如:{id:3,username:'admin'}

用户的信息经过加密后,就是payload部分队员的字符串

header+signature只是为了保证token的安全性。

3. JWT的使用方式

客户端将接收到的token存储到localstorage或者sessionstorage,客户端再次发起请求时,通过请求头的Authorization字段,将token发送给服务器

格式如下:

Authorization: Bearer <token>
复制代码

npm install jsonwebtoken express-jwt

  • jsonwebtoken: 用于生产JWT字符串

  • express-jwt: 用于将JWT字符串解析还原成JSON对象

// 导入用于生产JWT字符串的包
const jwt = require('jsonwebtoken')
// 导入用于将客户端发送过来的JWT字符串,解析还原车管JSON对象的包
const expressJWT = require('express-jwt');
复制代码

4. 定义secret密钥

为了保证JWT字符串的安全性,防止JWT字符串在网络传输中被比尔破解,需要撞门定义一个用于加密和解密的secret密钥

分类:
前端
收藏成功!
已添加到「」, 点击更改