git代码管理+nodejs+ES6+HTTP+包管理工具

113 阅读42分钟

1、Linux

1.1、简介

Linux是一套开源免费的操作系统。与系统交互通常使用命令实现,如果没有任何输出表明成功, 如果出现 error, fatal 表明执行失败

1.2、Linux常用命令

  • 命令描述
    ls查看文件夹下的文件(list 单词缩写)
    cd进入某一个文件夹内
    cd..回到上一级
    clear清屏(快捷键ctrl + l)
    mkdir创建文件夹(make directory)
    touch创建一个文件
    rm删除一个文件(remove)
    rm dir -r删除文件夹(-r删除文件夹选项 -f强制)force
    mv移动文件,重命名,move
    cat查看文件内容
    ctrl+c取消命令
    Tab自动补齐路径
    上下方向键查看历史命令
    history查看所有的历史命令
    ctrl + insert复制
    shift + insert粘贴
    ipconfig获取本机 IP 的方式

1.3、vim

  • vim是一款命令行下的文本编辑器,编辑方式和图形化编辑器不一样

    • 命令描述
      vim编辑文件(文件不存在则创建)
      i进入编辑模式(i insert )
      esc + :wq保存并退出
      esc + :q!不保存并退出

2、git

2.1、git简介

Git是一款开源免费的分布式的版本控制系统,是一个应用程序。下载地址 <git-scm.com/

2.2、git的作用

版本控制系统在项目开发中作用重大,主要的功能有以下几点

  • 代码备份
  • 版本回退
  • 协作开发
  • 权限控制

2.3、git的配置

第一次使用Git的时候,会要求我们配置用户名和邮箱,用于表示开发者的信息

git config --global user.name "Your Name" 
​
git config --global user.email "email@example.com" 
  • 注意命令之间的空格
  • 可以使用git config -l 命令来查看配置信息

2.4、git基本使用

  1. git init 仓库初始化
  2. 创建一个初始化文件 index.html
  3. git add index.html 将文件加入暂存区
  4. git commit -m '注释' 提交到仓库 m 是 message 单词的缩写

2.5、.git目录

文件描述
hooks目录包含客户端和服务端的钩子脚本,在特定操作下自动执行
info信息文件夹,包含一个全局性排除文件,可以配置文件忽略
logs保存日志信息
objects目录储存所有数据文件,本地的版本库存放位置
refs目录储存指向数据的提交对象的指针(分支)
config文件包含项目特有的配置选项
description用来显示对仓库的描述
HEAD文件指示目前被检出的分支
index暂存区文件,是一个二进制文件(git ls-files)
  • 切记:不要手动去修改,.git文件夹的内容

2.6、git版本库的三个区域

  • 工作区(代码编辑区)
  • 暂存区(修改待提交区)
  • 仓库区(代码保存区)

2.7、git常用命令

命令描述
git status版本状态查看(红色修改只存在工作区,绿色修改只存在工作区和暂存区)
git add -A添加所有新文件到暂存区
git commit -m '注释 '提交修改并注释
git ls-files查看暂存区的文件内容
git diff查看工作区与暂存区的差异(不显示新增文件) 显示做了哪些修改
git diff --cached查看暂存区与仓库的差异
git log查看历史记录
git reset --hard b815fd5a6ae655b521a31a9根据版本号进行回滚,进行版本回退时,不需要使用完整的哈希字符串,前七位即可。版本切换之前,要提交当前的代码状态到仓库
git reflog查看所有的操作记录
git rm --cached版本库中删除文件
git clone会将仓库的所有的分支全部下载下来
git pull只会拉取指定的分支内容

2.8、配置忽略文件

项目中有些文件不应该存储到版本库中,Git 中需要创建一个文件 『.gitignore』 配置忽略,一般与 .git 目录同级。

常见情况有:

  1. 临时文件.
  2. 多媒体文件,如音频,视频
  3. 编辑器生成的配置文件 (.idea)
  4. npm 安装的第三方模块
# 忽略所有的 .idea 文件夹
.idea
# 忽略所有以 .test 结尾的文件
*.test
# 忽略 node_modules 文件和文件夹
/node_modules

2.9、git分支

分支是 Git 重要的功能特性之一,开发人员可以在主开发线的基础上分离出新的开发线。branch

基本操作

命令描述
git branch name创建分支(name 为分支的名称)
git branch查看分支
git checkout name切换分支
git merge name合并分支
git branch -d name删除分支
git checkout -b name创建并切换分支
  • 每次在切换分支前 提交一下当前分支

2.10、git冲突

当多个分支修改同一个文件后,合并分支的时候就会产生冲突。冲突的解决非常简单,『将内容修改为最终想要的结果』,然后继续执行 git add 与 git commit 就可以了。

3、GitHub

GitHub 是一个 Git 仓库管理网站。可以创建远程中心仓库,为多人合作开发提供便利。

3.1、本地有仓库

  1. 注册并激活账号

  2. 创建仓库

  3. 获取仓库的地址

  4. 本地配置远程仓库的地址

    git remote add origin https://github.com/xiaohigh/test2.git  
    //remote 遥远的 远程
    //add  添加
    //origin 远端仓库的别名
    //https://github.com/xiaohigh/test2.git    仓库地址
    
  5. 本地提交(确认代码已经提交到本地仓库)

  6. 将本地仓库内容推送到远程仓库

    git push -u origin master
    //push 推送
    //-u   关联, 加上以后,后续提交时可以直接使用 git push
    //origin 远端仓库的别名
    //master 本地仓库的分支
    

3.2、本地没有仓库

  1. 注册并激活账号

  2. 克隆仓库

    git clone https://github.com/xiaohigh/test2.git 
    
  3. 增加和修改代码

  4. 本地提交

    git add -A
    git commit -m 'message'
    
  5. 推送到远程

    git push origin master
    

    克隆代码之后, 本地仓库会默认有一个远程地址的配置, 名字为 origin

3.3、多人合作

GitHub 团队协作开发也比较容易管理,可以创建一个组织

  • 首页 -> 右上角 + 号-> new Organization
  • 免费计划
  • 填写组织名称和联系方式(不用使用中文名称)
  • 邀请其他开发者进入组织(会有邮件邀请)
  • 点击组织右侧的 settings 设置
  • 左侧 Member privileges
  • 右侧 Base permissions 设置 write 👌

协作流程

第一次

  • 得到 Git 远程仓库的地址和账号密码

  • 将代码克隆到本地(地址换成自己的)

    git clone https://github.com/xiaohigh/test.git
    
  • 切换分支

    git checkout -b xiaohigh
    
  • 开发代码

  • 本地提交

    git add -A
    git commit -m '注释内容'
    
  • 合并分支

    git checkout master
    git merge xiaohigh
    
  • 更新本地代码

    git pull
    
  • 提交代码

    git push 
    

第二次流程

  1. 更新代码

    git checkout master
    git pull
    
  2. 切换并合并分支

    git checkout xiaohigh
    git merge master
    
  3. 开发功能

  4. 提交

    git add -A
    git commit -m '注释'
    
  5. 合并分支

    git checkout master
    git merge xiaohigh
    
  6. 更新代码

    git pull
    
  7. 推送代码

    git push
    

3.4、冲突解决

同分支冲突一样的处理,将代码调整成最终的样式,提交代码即可。

4、GitFlow

GitFlow 是团队开发的一种最佳实践,将代码划分为以下几个分支

  • Master 主分支。上面只保存正式发布的版本
  • Hotfix 线上代码 Bug 修复分支。开发完后需要合并回Master和Develop分支,同时在Master上打一个tag
  • Feather 功能分支。当开发某个功能时,创建一个单独的分支,开发完毕后再合并到 dev 分支
  • Release 分支。待发布分支,Release分支基于Develop分支创建,在这个Release分支上测试,修改Bug
  • Develop 开发分支。开发者都在这个分支上提交代码

首次克隆完代码后,需要切换到开发分支

//查看所有分支
git branch -a
//切换分支
git checkout  dev

5、ES5严格模式

ES5 除了正常运行模式(又称为混杂模式),还添加了第二种运行模式:"严格模式"(strict mode)。

严格模式顾名思义,就是使 JavaScript 在更严格的语法条件下运行。

5.1、作用

  1. 消除 JavaScript 语法的一些不合理、不严谨之处,减少一些怪异行为
  2. 消除代码运行的一些不安全之处,保证代码运行的安全
  3. 为未来新版本的 JavaScript 做好铺垫

5.2、使用

  • 在全局或函数的第一条语句定义为: 'use strict'
  • 如果浏览器不支持,只解析为一条简单的语句, 没有任何副作用
  • // 全局使用严格模式
    'use strict';
    girl = '迪丽热巴';
    ​
    // 函数中使用严格模式
    function main(){
        'use strict';
        boy = '吴亦凡';
    }
    main();
    

5.3、语法和行为改变

  • 必须用 var 声明变量,不允许使用未声明的变量
  • 禁止自定义的函数中的 this 指向 window
  • 创建 eval 作用域
  • 对象不能有重名的属性(Chrome 已经修复了这个 Bug,IE 还会出现)
  • 函数不能有重复的形参
  • 新增一些保留字, 如: implements interface private protected public

6、Object 扩展方法

Object.create(prototype, [descriptors])

Object.create 方法可以以指定对象为原型创建新的对象,同时可以为新的对象设置属性, 并对属性进行描述

  • value : 指定值
  • writable : 标识当前属性值是否是可修改的, 默认为 false
  • configurable:标识当前属性是否可以被删除 默认为 false
  • enumerable:标识当前属性是否能用for in 枚举 默认为 false
  • get: 当获取当前属性时的回调函数
  • set: 当设置当前属性时
//创建一个汽车的对象
var car = {
    name : '汽车',
    run: function(){
        console.log('我可以行驶!!');
    }
};
​
//以 car 为原型对象创建新对象
var aodi = Object.create(car, {
    brand: {
        value: '奥迪',
        writable: false,         //是否可修改
        configurable: false,     //是否可以删除
        enumerable: true         //是否可以使用 for...in 遍历
    },
    color: {
        value : '黑色',
        wriable: false,
        configurable: false,
        enumerable: true
    }
});

Object.defineProperties(object, descriptors)

直接在一个对象上定义新的属性或修改现有属性,并返回该对象。

  • object 要操作的对象

  • descriptors 属性描述

    • get 作为该属性的 getter 函数,如果没有 getter 则为undefined。函数返回值将被用作属性的值。
    • set 作为属性的 setter 函数,如果没有 setter 则为undefined。函数将仅接受参数赋值给该属性的新值。
// 定义对象
var star = {
    firstName: '刘',
    lastName : '德华'
};

// 为 star 定义额外的属性
Object.defineProperties(star, {
    fullName: {
        get: function(){
            return this.firstName + this.lastName;
        },
        set: function(name){
            var res = name.split('-');
            this.firstName = res[0];
            this.lastName = res[1];
        }
    }
});

// 修改 fullName 属性值
star.fullName = '张-学友';

// 打印属性
console.log(star.fullName);

7、call、apply 和 bind

  • call 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数
  • apply 方法调用一个具有给定 this 值的函数,以及作为一个数组(或类似数组对象)提供的参数
  • bind 同 call 相似,不过该方法会返回一个新的函数,而不会立即执行
function main(){
    console.log(this);
}
/*1. 直接调用函数*/
main();										//  window
/*2. 创建一个对象*/
var company = {name: '尚硅谷', age: 10};
/*使用这个对象调用 main 方法*/
main.call(company);							// company
main.apply(company);						// company
/*bind 修改 this 的值,返回一个新的函数*/
var fn = main.bind(company);
fn();										// company

8、ES6

ECMA(European Computer Manufacturers Association)中文名为欧洲计算机制造商协会,这个组织的目标是评估、开发和认可电信和计算机标准。1994年后该组织改名为Ecma国际。

ECMAScript 是由Ecma国际通过ECMA-262标准化的脚本程序设计语言

Ecma国际制定了许多标准,而ECMA-262只是其中的一个

8.1、 let关键字

let关键字用来声明变量,使用let声明的变量有几个特点:

  • 不允许重复声明
  • 块儿级作用域
  • 不存在变量提升

应用场景:以后声明变量使用let* 就对了*

8.2、const关键字

const 关键字用来声明常量,const声明有以下特点

  • 声明一定要赋初始值
  • 不允许重复声明
  • 值不允许修改
  • 块儿级作用域

注意:

  • 常量的名称一般为 『大写』 潜规则
  • 对象属性修改和数组元素变化不会出发const错误
  • 应用场景:声明对象类型使用const,非对象类型声明选择let
  • //6. 关于数组和对象的元素的修改
    const TEAM = ['UZI','MLXG','LETME'];
    TEAM.push('XIYE');
    console.log(TEAM);
    const BIN = {
        name: 'BIN'
    }
    BIN.name = '阿斌';
    console.log(BIN);
    

8.3、 变量的解构赋值

ES6允许按照一定模式从数组和对象中提取值,对变量进行赋值,这被称为解构赋值

const arr = ['张学友', '刘德华', '黎明', '郭富城'];
let [zhang, liu, li, guo] = arr;
const lin = {
    name: '林志颖',
    tags: ['车手', '歌手', '小旋风', '演员']
};
let {name, tags} = lin;

//复杂解构
let wangfei = {
    name: '王菲',
    age: 18,
    songs: ['红豆', '流年', '暧昧', '传奇'],
    history: [
        {name: '窦唯'},
        {name: '李亚鹏'},
        {name: '谢霆锋'}
    ]
};
let {songs: [one, two, three], history: [first, second, third]} = wangfei;

注意:频繁使用对象方法、数组元素,就可以使用解构赋值形式

8.4、 模板字符串

模板字符串(template string)是增强版的字符串,用反引号(`)标识,特点:

  • 字符串中可以出现换行符
  • 可以使用 ${xxx} 形式输出变量
  • //1. 直接使用换行符
    let str = `<ul>
                    <li>沈腾</li>
                    <li>马丽</li>
                    <li>艾伦</li>
                    <li>魏翔</li>
                </ul>`;
    //2. 字符串中进行变量拼接
    let star = '魏翔';
    let str2 = `我特别喜欢 ${star}, 搞笑风格诡异`;
    

当遇到字符串与变量拼接的情况使用模板字符串

8.5、简化对象写法

ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁

let name = '尚硅谷';
	let pos = '北京';
	let change = function(){
		console.log('改变');
	}

const atguigu = {
	name,
	pos,
	change,
	improve(){
		console.log('提升');
	}
}
console.log(atguigu)

注意:对象简写形式简化了代码,所以以后用简写就对了

8.6、箭头函数

ES6 允许使用「箭头」(=>)定义函数。

let fn = (arg1, arg2, arg3) => {
    return arg1 + arg2 + arg3;
}

箭头函数的注意点:

  • 箭头函数this指向声明时所在作用域下 this 的值
  • 箭头函数不能作为构造函数实例化
  • 箭头函数内没有arguments
  • 如果形参有且只有一个,则小括号可以省略
  • 函数体如果只有一条语句,则花括号可以省略,函数的返回值为该条语句的执行结果(如果不写花括号的话, return 也不能写)
//2. 省略小括号的情况
let fn2 = num => {
    return num * 10;
};
//3. 省略花括号的情况
let fn3 = score => score * 20;
//4. this指向声明时所在作用域中 this 的值
let fn4 = () => {
    console.log(this);
}
let school = {
    name: '尚硅谷',
    getName(){
        let fn5 = () => {
            console.log(this);
        }
        fn5();
    }
};

箭头函数不会更改this指向,所以非常适合设置与this无关的回调,比如数组回调、定时器回调,不适合事件回调与对象方法。

8.7、rest参数

ES6引入rest参数,用于获取函数的实参,用来代替arguments

//作用与 arguments 类似
function add(...args){
    console.log(args);
}
add(1,2,3,4,5);
//rest 参数必须是最后一个形参
function minus(a,b,...args){
    console.log(a,b,args);
}
minus(100,1,2,3,4,5,19);

注意:rest****参数非常适合不定个数参数函数的场景

8.8、spread扩展运算符

扩展运算符(spread)也是三个点(...)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列,对数组进行解包。

//展开数组
let tfboys = ['德玛西亚之力','德玛西亚之翼','德玛西亚皇子'];
function fn(){
    console.log(arguments);
}
fn(...tfboys)
//展开对象
let skillOne = {
    q: '致命打击',
};
let skillTwo = {
    w: '勇气'
};
let skillThree = {
    e: '审判'
};
let skillFour = {
    r: '德玛西亚正义'
};
let gailun = {...skillOne, ...skillTwo,...skillThree,...skillFour};

8.9、Symbol

ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型。

Symbol特点:

  • Symbol的值是唯一的,用来解决命名冲突的问题
  • Symbol值不能与其他数据进行运算
//创建 Symbol
let s1 = Symbol();
console.log(s1, typeof s1);

//添加标识的 Symbol
let s2 = Symbol('尚硅谷');
let s2_2 = Symbol('尚硅谷');
console.log(s2 === s2_2);

//使用 Symbol for 定义
let s3 = Symbol.for('尚硅谷');
let s3_2 = Symbol.for('尚硅谷');
console.log(s3 === s3_2);

Symbol类型唯一合理的用法是用变量存储 symbol的值,然后使用存储的值创建对象属性

8.10、迭代器

迭代器(Iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。

  1. ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of消费

  2. 原生具备iterator接口的数据(可用for of遍历)

    • Array
    • Arguments
    • Set
    • Map
    • String
    • TypedArray
    • NodeList
  3. 工作原理

    1. 创建一个指针对象,指向当前数据结构的起始位置
    2. 第一次调用对象的next方法,指针自动指向数据结构的第一个成员
    3. 接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员
    4. 每调用next方法返回一个包含value和done属性的对象
const arr = ['刘德华','黎明','郭富城','张学友'];

//for...of 遍历
for(let v of arr) {
	console.log(v);
}

需要自定义遍历数据的时候,要想到迭代器。

8.11、Promise

Promise是ES6引入的异步编程的新解决方案。语法上Promise是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。

8.12、Set

ES6 提供了新的数据结构 Set(集合)。它类似于数组,但成员的值都是唯一的,集合实现了iterator接口,所以可以使用『扩展运算符』和『for…of…』进行遍历,

集合的属性和方法描述
size返回集合的元素个数
add增加一个新元素,返回当前集合
delete删除元素,返回boolean 值
has检测集合中是否包含某个元素,返回boolean值
clear清空集合,返回undefined
//创建一个空集合
let s = new Set();
//创建一个非空集合
let s1 = new Set([1,2,3,1,2,3]);
​
//集合属性与方法
//返回集合的元素个数
console.log(s1.size);
//添加新元素
console.log(s1.add(4));
//删除元素
console.log(s1.delete(1));
//检测是否存在某个值
console.log(s1.has(2));
//清空集合
console.log(s1.clear());

实践:

 //1. 数组去重  
        const arr = ['大事儿','小事儿','好事儿','坏事儿','小事儿'];
        //集合
        // const s = new Set(arr);
        // const result = [...s];
        // console.log(result);
​
        //2. 交集
        const arr1 = [1,2,3,4,5,1,2];
        const arr2 = [3,4,5,4,5,6];
​
        // const result = [...new Set(arr1)].filter(item => {
        //     return (new Set(arr2)).has(item);
        // });
        // console.log(result);
​
        //3. 并集
        // const result = [...new Set([...new Set(arr1),...new Set(arr2)])];
​
        //4. 差集
        const result = [...new Set(arr1)].filter(item => {
            return !(new Set(arr2)).has(item);
        });
        console.log(result);

8.13、Map

ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合。但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map也实现了iterator接口,所以可以使用『扩展运算符』和『for…of…』进行遍历。

Map的属性和方法描述
size返回Map的元素个数
set增加一个新元素,返回当前Map
get返回键名对象的键值
has检测Map中是否包含某个元素,返回boolean值
clear清空集合,返回undefined
//创建一个空 map
let m = new Map();
//创建一个非空 map
let m2 = new Map([
    ['name','尚硅谷'],
    ['slogon','不断提高行业标准']
]);

//属性和方法
//获取映射元素的个数
console.log(m2.size);
//添加映射值
console.log(m2.set('age', 6));
//获取映射值
console.log(m2.get('age'));
//检测是否有该映射
console.log(m2.has('age'));
//清除
console.log(m2.clear());

8.14、class类

ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。基本上,ES6 的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。

知识点:

  • class声明类
  • constructor定义构造函数初始化
  • extends继承父类
  • super调用父级构造方法
  • static定义静态方法和属性
  • 父类方法可以重写
//父类
class Phone {
    //构造方法
    constructor(brand, color, price) {
        this.brand = brand;
        this.color = color;
        this.price = price;
    }
    //对象方法
    call() {
        console.log('我可以打电话!!!')
    }
}
//子类    extends 继承
class SmartPhone extends Phone {
    //构造方法
    constructor(brand, color, price, screen, pixel) {
        //调用父类的构造方法 属性初始化
        super(brand, color, price);
        this.screen = screen;
        this.pixel = pixel;
    }
    //子类方法
    photo(){
        console.log('我可以拍照!!');
    }
    playGame(){
        console.log('我可以玩游戏!!');
    }
    //方法重写
    call(){
        console.log('我可以进行视频通话!!');
    }
    //静态方法
    static run(){
        console.log('我可以运行程序')
    }
    static connect(){
        console.log('我可以建立连接')
    }
}
//实例化对象
const Nokia = new Phone('诺基亚', '灰色', 230);
const iPhone6s = new SmartPhone('苹果', '白色', 6088, '4.7inch','500w');
//调用子类方法
iPhone6s.playGame();
//调用重写方法
iPhone6s.call();
//调用静态方法
SmartPhone.run();

8.15、数值扩展

代码描述
二进制0b开头
八进制0o开头
Number.isFinite()用来检查一个数值是否为有限的
Number.isNaN()用来检查一个值是否为NaN
Number.parseInt()将一个字符串解析为一个整数
Number.parseFloat()将一个字符串加息为一个小数
Math.trunc用于去除一个数的小数部分,返回整数部分
Number.isInteger用来判断一个数值是否为整数

8.16、对象扩展

ES6新增Object对象的方法描述
Object.is比较两个值是否严格相等,与『===』行为基本一致(+0 与 NaN)
Object.assign对象的合并,将源对象的所有可枚举属性,复制到目标对象
__ proto __ setPrototypeOf setPrototypeOf可以直接设置对象的原型

9、Nodejs

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,是一个应用程序。官方网址 nodejs.org/en/,中文站 nodejs.cn/

在 nodejs 环境下,不能使用 BOM 和 DOM ,也没有全局对象 window,全局对象的名字叫 global

9.1、Nodejs作用

  • 解析运行 JS 代码
  • 操作系统资源,如内存、硬盘、网络

9.2、Nodejs应用场景

  • APP 接口服务
  • 网页聊天室
  • 动态网站, 个人博客, 论坛, 商城等
  • 后端的Web服务,例如服务器端的请求(爬虫),代理请求(跨域)
  • 前端项目打包(webpack, gulp)

9.3、下载安装

  • Nodejs 的版本号奇数为开发版本,偶数为发布版本,我们选择偶数号的 LTS 版本(长期维护版本 long term service)
  • 安装完成后,在 CMD 命令行窗口下运行 node -v,如显示版本号则证明安装成功,反之安装失败,重新安装。

10、Buffer(缓冲器)

Buffer 是一个和数组类似的对象,不同是 Buffer 是专门用来保存二进制数据的

特点:

  • 大小固定:在创建时就确定了,且无法调整
  • 性能较好:直接对计算机的内存进行操作
  • 每个元素大小为 1 字节(byte)
  • 溢出的高位数据会舍弃
  • 一个 UTF-8 的中文字符大多数情况都是占 3 个字节

10.1、创建 Buffer

  • 直接创建 Buffer.alloc
  • 不安全创建 B10.1uffer.allocUnsafe
  • 通过数组和字符串创建 Buffer.from

10.2、Buffer 读取和写入

可以直接通过 [] 的方式对数据进行处理,可以使用 toString 方法将 Buffer 输出为字符串

  • ==[ ]== 对 buffer 进行读取和设置
  • ==toString== 将 Buffer 转化为字符串

10.3、关于单位换算

  • 1Bit 对应的是 1 个二进制位
  • 8 Bit = 1 字节(Byte)
  • 1024Byte = 1KB
  • 1024KB = 1MB
  • 1024MB = 1GB
  • 1024GB = 1TB

平时所说的网速 10M 20M 100M 这里指的是 Bit ,所以理论下载速度 除以 8 才是正常的理解的下载速度

11、fs文件系统

fs 全称为 file system,是 NodeJS 中的内置模块,可以对计算机中的文件进行增删改查等操作。

单词含义:

  • File 文件
  • data 要写入的数据
  • options 可选项
  • callback 回调函数
  • path 路径

简单文件写入

  • fs.writeFile(file, data, [,options], callback); 文件写入(异步)

    • options 可选项

      • encoding 默认值: utf8
      • mode 默认值: 0o666
      • flag 默认值:w (a,写入不覆盖)
  • fs.writeFileSync(file, data); 文件写入(同步)

流式写入

  • fs.createWriteStream(path[, options])

    • options

      • flags 默认值: w(a,写入不覆盖)
      • `encoding 默认值: ‘utf8’
      • mode 默认值: ‘0o666’
    • 事件监听 open close eg: ws.on('open', function(){});

文件读取

  • 简单读取

    • fs.readFile(file, function(err, data){})
    • fs.readFileSync(file)
  • 流式读取

    • fs.createReadStream();
文件删除
  • fs.unlink('./test.log', function(err){});
  • fs.unlinkSync('./move.txt');
移动文件 + 重命名
  • fs.rename('./1.log', '2.log', function(err){})
  • fs.renameSync('1.log','2.log')
文件夹操作
  • mkdir 创建文件夹

    • path

    • options

      • recursive 是否递归调用
      • mode 权限 默认为 0o777
    • callback

  • rmdir 删除文件夹

  • readdir 读取文件夹

12、HTTP协议简介

HTTP(hypertext transport protocol)协议也叫==超文本传输协议==,是一种基于 TCP/IP 的应用层通信协议,这个协议详细规定了浏览器和万维网服务器之间互相通信的规则。

协议主要规定了两方面的内容

  • 客户端向服务器发送数据,称之为==请求报文==
  • 服务器向客户端返回数据,称之为==响应报文==

12.1、端口号

  • 计算的服务窗口 总共65536端口
  • HTTP服务常用端口 8000 3000 9000 8080
  • HTTP 默认端口 80

12.2、HTTP请求报文

HTTP 请求报文包括四部分:

  • 请求行
  • 请求头
  • 空行
  • 请求体
GET http://localhost:3000/index.html?username=sunwukong&password=123123 HTTP/1.1
Host: localhost:3000
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
  • GET http://localhost:3000/hello.html HTTP/1.1:GET请求,请求服务器路径为http://localhost:3000/hello.html,?后面跟着的是请求参数(查询字符串),协议是HTTP 1.1版本
  • Host: localhost:3000:请求的主机名为localhost,端口号3000
  • Connection: keep-alive:处理完这次请求后继续保持连接,默认为3000ms
  • Pragma: no-cache:不缓存该资源,http 1.0的规定
  • Cache-Control: no-cache: 不缓存该资源 http 1.1的规定,优先级更高
  • Upgrade-Insecure-Requests: 1:告诉服务器,支持发请求的时候不用 http 而用 https
  • User-Agent: Mozilla/5.0 (...:与浏览器和OS相关的信息。有些网站会显示用户的系统版本和浏览器版本信息,这都是通过获取User-Agent头信息而来的
  • Accept: text/html,...:告诉服务器,当前客户端可以接收的文档类型。q 相当于描述了客户端对于某种媒体类型的喜好系数,该值的范围是 0-1。默认为1
  • Accept-Encoding: gzip, deflate, br:支持的压缩格式。数据在网络上传递时,服务器会把数据压缩后再发送
  • Accept-Language: zh-CN,zh;q=0.9:当前客户端支持的语言,可以在浏览器的工具选项中找到语言相关信息

12.3、url

https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1#logo
  • https/http/mongodb/ftp/ssh 协议
  • www.baidu.com 域名(IP地址)
  • /s 路径
  • ie=utf-8&f=8&rsv_bp=1&rsv_idx=1 查询字符串(query string) name=煎饼果子&is_lajiao=0&conghua=1&xiangcai=0
  • #logo 锚点

12.4、请求报文补充

  • 每一款浏览器的 user-agent 值都是不一样的
  • GET 请求请求体是空的, 但是 POST 请求请求体一般不为空

12.5、HTTP响应报文

HTTP 响应报文也包括四个部分

  • 响应行
  • 响应头
  • 空行
  • 响应体
HTTP/1.1 200 OK
X-Powered-By: Express
Accept-Ranges: bytes
Cache-Control: public, max-age=0
Last-Modified: Wed, 21 Mar 2018 13:13:13 GMT
ETag: W/"a9-16248b12b64"
Content-Type: text/html; charset=UTF-8
Content-Length: 169
Date: Thu, 22 Mar 2018 12:58:41 GMT
Expires: Sat, 07 Nov 2020 03:08:03 GMT
Connection: keep-alive
Server: BWS/1.1
​
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>首页</title>
</head>
<body>
  <h1>网站首页</h1>
</body>
</html>
  • HTTP/1.1 200 OK:协议是HTTP 1.1版本,请求响应成功

  • X-Powered-By: Express:自定义的头,表示用的框架,一般不返回容易造成安全漏洞。

  • Accept-Ranges: bytes:告诉浏览器支持多线程下载

  • Cache-Control: public, max-age=0:强制对所有静态资产进行缓存,即使它通常不可缓存。max-age指定多久缓存一次

  • Last-Modified: Wed, 21 Mar 2018 13:13:13 GMT:这个资源最后一次被修改的日期和时间

  • ETag: W/"a9-16248b12b64":请求资源的标记/ID

  • Content-Type:> text/html; charset=UTF-8:返回响应体资源类型

    • text/html 表明响应体为 HTML 内容
    • text/css 表明响应体为 CSS 内容
    • application/javascript 表明响应体为 JavaScript
    • image/png 表明响应体为 png 的图片
  • Content-Length: 169:响应体的长度

  • Date: Thu, 22 Mar 2018 12:58:41 GMT:提供了日期的时间标志,标明响应报文是什么时间创建的

  • Expires 过期时间

  • Server 服务器信息

12.6、常见的响应状态码:

响应状态码是服务器对结果的标识,常见的状态码有以下几种:

  • 200:请求成功,浏览器会把响应体内容(通常是html)显示在浏览器中;
  • 301:重定向,被请求的旧资源永久移除了(不可以访问了),将会跳转到一个新资源,搜索引擎在抓取新内容的同时也将旧的网址替换为重定向之后的网址;
  • 302:重定向,被请求的旧资源还在(仍然可以访问),但会临时跳转到一个新资源,搜索引擎会抓取新的内容而保存旧的网址;
  • 304:(Not Modified)请求资源未被修改,浏览器将会读取缓存;
  • 403:forbidden 禁止的
  • 404:请求的资源没有找到,说明客户端错误的请求了不存在的资源;
  • 500:请求资源找到了,但服务器内部出现了错误;
信息响应(100199),
成功响应(200299),
重定向(300399),
客户端错误(400499)
服务器错误 (500599)

12.7、GET 和 POST 的区别

  • GET 主要用来获取数据, POST 主要用来提交数据
  • GET 带参数请求是将参数缀到 URL 之后, 在地址栏输入url访问网站就是 GET 请求, POST 带参数请求是将参数放到请求体中
  • POST 请求相对 GET 安全一些, 因为在浏览器中参数会暴露在地址栏.
  • GET 请求大小有限制, 一般为 2k, 而 POST 请求则没有大小限制
  • GET 类型报文请求方法的位置为 GET , POST 类型报文请求方法为 POST

13、web服务

13.1、创建http内置模块

  • request 是对请求报文的封装对象
  • response 是对响应的封装对象
//1. 引入 http 内置模块
var http = require('http');

//2. 创建服务
var server = http.createServer(function(request, response){
    response.end('hello world!!');
});

//3. 监听端口
server.listen(8000);

13.2、获取请求

//获取请求方法
console.log(request.method);
​
//获取http版本
console.log(request.httpVersion);
​
//获取请求路径
console.log(request.url);
​
//获取请求头
console.log(request.headers);
​
//获取请求体
request.on('data', function(chunk){})
request.on('end', function(){});

13.3、设置响应

//设置状态码
response.statusCode = 200;
​
//设置响应头
response.setHeader('content-type','text/html;charset-utf-8');
​
//设置响应体
response.write('body');
​
//结束
response.end();
​

14、chrome查看请求报文和响应报文

  • Network 网络 / 互联网

    • Headers 请求和响应的栏目

      • General 大概情况/预览
      • Response Headers 响应行与响应头
      • Request Headers 请求行与请求头
      • Form Data 请求体
    • Preview 响应结果的格式化预览

    • Response 原始响应体

15、NPM(包管理工具)

全称:Node Package Manager , Node 的包管理器,也是一个应用程序。

包是什么

Node.js 的包基本遵循 CommonJS 规范,将一组相关的模块组合在一起,形成一个完整的工具

作用

通过 NPM 可以对 Node 的工具包进行搜索、下载、安装、删除、上传。借助别人写好的包,可以让我们的开发更加方便。

安装

安装完 nodejs 之后会自动安装 npm

查看 npm 的版本

npm -v 

初始化

npm init
npm init --yes

运行后会创建 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"      #版权声明
}

==注意生成的包名不能使用中文,大写 !!! 不能使用 npm 作为包的名字==

安装工具包

npm install jquery
npm i jquery
​
# 安装并在 package.json 中保存包的信息(dependencies 属性)
npm install jquery --save
npm install jquery -S
​
# 安装并在 package.json 中保存包的信息(devDependencies 属性)
npm install babel --save-dev
npm install babel -D
​

6 版本的 npm ,安装包时会自动保存在 dependencies 中,可以不用写 --save

全局安装

npm install less -g
npm install nodemon -g 

全局安装一般用于安装全局工具,如 cnpm,yarn,webpack ,gulp等,全局命令的安装位置

C:\Users\你的用户名\AppData\Roaming\npm

全局安装命令在任意的命令行下, 都可以执行

安装依赖

根据 package.json 中的依赖声明, 安装工具包

npm i
npm install
npm i --production // 只安装 dependencies 中的依赖

移除包

npm remove jquery

使用流程

团队开发时使用流程

  1. 从仓库中拉取仓库代码
  2. ==运行 npm install 安装相关依赖==
  3. 运行项目,继续开发

封装 NPM 包

创建自己的 NPM 包可以帮助代码进行迭代进化,使用步骤也比较简单

  1. 修改为官方的地址 (npm config set registry registry.npmjs.org/)
  2. 创建文件夹,并创建文件 index.js, 在文件中声明函数,使用 module.exports 暴露
  3. npm 初始化工具包,package.json 填写包的信息
  4. 账号注册(激活账号),==完成邮箱验证==
  5. 命令行下 『npm login』 填写相关用户信息
  6. 命令行下『 npm publish』 提交包 👌

npm 有垃圾检测机制,如果名字简单或做测试提交,很可能会被拒绝提交

==可以尝试改一下包的名称来解决这个问题==

升级 NPM 包,需要修改 package.json 中的版本号修改,只需要执行『npm publish』就可以能提交

  1. 修改包代码
  2. 修改 package.json 中版本号
  3. npm publish 提交

删除 npm 包

npm unpublish 包名 --force

npm 清除缓存

npm cache clean

-S

会将安装的包的信息,记录在 package.json 中的 dependencies 属性

dependencies  生产依赖

-D

会将安装的包的信息,记录在 package.json 中的 devDependencies 属性

devDependencies    开发依赖

node_modules 目录是不能进入 Git 仓库的

16、CNPM

介绍

cnpm 是淘宝对国外 npm 服务器的一个完整镜像版本,也就是淘宝 npm 镜像,网站地址npm.taobao.org/

安装

安装配置方式有两种

  • npm install -g cnpm --registry=registry.npm.taobao.org
  • alias cnpm="npm --registry=registry.npm.taobao.org \ --cache=HOME/.npm/.cache/cnpm disturl=<https://npm.taobao.org/dist> userconfig=HOME/.npm/.cache/cnpm \ --disturl=<https://npm.taobao.org/dist> \ --userconfig=HOME/.cnpmrc" (只能在Linux下使用)

使用

配置完成后,就可以使用 cnpm 命令来管理包,使用方法跟 npm 一样

cnpm install lodash

npm 配置镜像地址

//淘宝镜像
npm config set registry https://registry.npm.taobao.org
//官方镜像   
npm config set registry https://registry.npmjs.org/

在发布工具的时候, 一定要将仓库地址, 修改为官方的地址

17、Yarn

介绍

yarn 是 Facebook 开源的新的包管理器,可以用来代替 npm。

特点

yarn 相比于 npm 有几个特点

  • 本地缓存。安装过的包下次不会进行远程安装
  • 并行下载。一次下载多个包,而 npm 是串行下载
  • 精准的版本控制。保证每次安装跟上次都是一样的

安装

yarn 安装

只需要一行命令即可安装 yarn

npm install yarn -g
msi 安装包安装

classic.yarnpkg.com/en/docs/ins…

相关命令

yarn 的相关命令

命令描述
yarn --version查看安装版本
yarn init初始化文件,生成package.json
yarn global add package(全局安装)
yarn global remove less(全局删除)
yarn add package(局部安装)
yarn add package --dev(相当于npm中的--save-dev)
yarn remove package局部删除
yarn list列出已经安装的包名 用的很少
yarn info packageName获取包的有关信息 几乎不用
yarn安装package.json中的所有依赖

npm 5 引入离线缓存,提高了安装速度,也引入了 package-lock.json 文件增强了版本控制

yarn 修改仓库地址

yarn config set registry https://registry.npm.taobao.org

18、CYarn

跟 npm 与 cnpm 的关系一样,可以为 yarn 设置国内的淘宝镜像,提升安装的速度

npm install cyarn -g --registry "https://registry.npm.taobao.org"

配置后,只需将yarn改为cyarn使用即可

19、关于版本号

版本格式:主版本号.次版本号.修订号

  • "^3.0.0" :锁定主版本,以后安装包的时候,保证包是3.x.x版本,x默认取最新的。
  • "~3.2.x" :锁定小版本,以后安装包的时候,保证包是3.1.x版本,x默认取最新的。
  • "3.1.1" :锁定完整版本,以后安装包的时候,保证包必须是3.1.1版本。

安装指定版本的工具包

yarn add jquery@1.11.2

20、模块化

模块化指的就是将一个大的功能拆分为一个一个小的模块,通过不同的模块的组合来实现一个大功能。

  • 在node中一个 js 文件就是一个模块
  • 模块内部代码对于外部来说都是不可见的,可以通过两种方式向外部暴露

20.1、模块创建

一、创建 JS 文件,编写代码(假设当前文件名为 test.js)

function test(){
	console.log('test');
}

二、在文件中对外暴露

module.exports = test;

这里有几点注意:

  • module.exports 可以暴露任意数据
  • 可以使用 module.exports 暴露多个数据
  • exports 也可以暴露数据,不过不能使用 exports = xxx 的形式

20.2、模块引入

使用 require 引入文件即可

var test = require('./test.js');

这里有几点注意:

  • 如果没有加文件后缀,会按照以下后缀加载文件

    • .js fs模块同步读取文件编译执行
    • .json fs模块同步读取文件,用JSON.parse()解析返回结果
    • .node 这是c/c++编写的扩展文件,通过dlopen()方法编译
  • 其他扩展名 会以.js文件载入

  • 如果是文件夹则会默认加载该文件夹下 package.json 文件中 main 属性对应的文件

  • 如果 main 属性对应的文件不存在,则自动找 index.js index.json

  • 如果是内置模块或者是 npm 安装的模块,直接使用包名字即可

  • npm 引入包时,如果当前文件夹下的 node_modules 没有,则会自动向上查找

20.3、简化

导出

module.exports       

导入

var res = require('./module.js');

21、Express

Express 是一个基于 Node.js 平台的极简、灵活的 web 应用开发框架,它提供一系列强大的特性,帮助你快速创建各种 Web 和移动设备应用。

简单来说Express就是运行在node中的用来搭建服务器的模块。

21.1、 Express的使用

express下载

  • npmi express --save 安装express并添加到依赖项

创建一个服务器

//引入express模块
var express = require('express')
//创建应用对象
var app = express()
//配置静态资源
app.use(express.static('public'))
//开启服务器,监听3000端口
app.listen(3000)    //默认端口号80

22、路由(Route)

路由是指如何定义应用的端点(URIs)以及如何响应客户端的请求。

路由是由一个 URI、HTTP 请求(GET、POST等)和若干个句柄组成的。

22.1、Route的定义

我们可以将路由定义为三个部分:

  • 第一部分:HTTP请求的方法(get或post)
  • 第二部分:URI路径
  • 第三部分: 回调函数

22.2、Route的实现

Express中提供了一系列函数,可以让我们很方便的实现路由:

app.<method>(path,callback) 
语法解析:
method指的是HTTP请求方法,比如:
app.get()
app.post()
path指要通过回调函数来处理的URL地址
callback参数是应该处理该请求并把响应发回客户端的请求处理程序

22.3、Route的实例

//引入express
var express = require('express')
//创建应用对象
var app = express()
//配置路由
app.get('/index', function (request, response) {
  console.log('路由index收到get请求')
  response.send('这里是路由返回的信息,/hello收到了get请求')
})
​
app.post('/index', function (request, response) {
  console.log('路由index收到post请求')
  response.send('这里是路由返回的信息,/hello收到了post请求')
})
​
//启动服务器
app.listen(3000, function () {
  console.log('服务器启动成功,监听3000端口')
})
​

22.4、Route的运行流程

当Express服务器接收到一个HTTP请求时,它会查找已经为适当的HTTP方法和路径定义的路由

如果找到一个,Request和Response对象会被创建,并被传递给路由的回调函数

我们便可以通过Request对象读取请求,通过Response对象返回响应

Express中还提供了all()方法,可以处理两种请求。

22.5、Request对象

Request对象是路由回调函数中的第一个参数,代表了用户发送给服务器的请求信息

通过Request对象可以读取用户发送的请求包括URL地址中的查询字符串中的参数,和post请求的请求体中的参数。

request属性/方法描述
request.query获取get请求查询字符串的参数,拿到的是一个对象
request.params获取get请求参数路由的参数,拿到的是一个对象
request.body获取post请求体,拿到的是一个对象(要借助一个中间件)
request.get(xxxx)获取请求头中指定key对应的value

22.6、Response对象

Response对象是路由回调函数中的第二个参数,代表了服务器发送给用户的响应信息。

通过Response对象可以设置响应报文中的各个内容,包括响应头和响应体。

response属性/方法描述
response.send()给浏览器做出一个响应
response.end()给浏览器做出一个响应(不会自动追加响应头)
response.download()告诉浏览器下载一个文件
response.sendFile()给浏览器发送一个文件
response.redirect()重定向到一个新的地址(url)
response.set(header,value)自定义响应头内容
res.status(code)设置响应状态码

23、中间件

Express 是一个自身功能极简,完全是由路由和中间件构成一个的 web 开发框架:从本质上来说,一个 Express 应用就是在调用各种中间件。

中间件(Middleware) 是一个函数,它可以访问请求对象(request), 响应对象(response), 和 web 应用中处于请求-响应循环流程中的中间件,一般被命名为 next 的变量。

23.1、中间件的功能

  1. 执行任何代码。
  2. 修改请求和响应对象。
  3. 终结请求-响应循环。
  4. 调用堆栈中的下一个中间件

23.2、中间件的分类

  1. 应用级中间件(过滤非法的请求,例如防盗链)
  2. 第三方中间件(通过npm下载的中间件,例如body-parser)
  3. 内置中间件(express内部封装好的中间件)
  4. 路由器中间件 (Router)

23.3、中间件实例

//引入express
var express = require('express')
//创建应用对象
var app = express()
//配置静态资源
app.use(express.static('public'))
//中间件,没有挂载路径,应用的每个请求都会执行该中间件
app.use(function (req, res, next) {
  console.log('这是中间件的响应~~~')
  //如果不调用next方法,下面路由将不起作用
  next()
})
//配置路由
app.get('/index', function (req, res) {
  console.log('路由index收到get请求')
  res.send('这里是路由返回的信息,/hello收到了get请求')
})
​
app.post('/index', function (req, res) {
  console.log('路由index收到post请求')
  res.send('这里是路由返回的信息,/hello收到了post请求')
})
​
//启动服务器
app.listen(3000, function () {
  console.log('服务器启动成功,监听3000端口')
})

24、Router路由器

Router 是一个完整的中间件和路由系统,也可以看做是一个小型的app对象。

24.1、为什么使用Router

为了更好的分类管理route

24.2、Router的实例

//引入express模块
var express = require('express');
//引入body-parser模块
var bodyParser = require('body-parser');
//引入Users模型对象
var Users = require('../models/Users');
//创建router对象
var router = express.Router();
//解析请求体,将参数挂在到req.body
router.use(bodyParser.urlencoded({extended: false}));
router.post('/login', function (req, res) {
  var username = req.body.username;
  var password = req.body.password;
  Users.findOne({username: username}, function (err, data) {
    if (!err && data && data.password === password) {
      res.send('恭喜您登录成功~~~');
    } else {
      res.send('用户名或密码错误~~~');
    }
  })
})
router.post('/regist', function (req, res) {
  //获取用户提交的参数
  var username = req.body.username;
  var password = req.body.password;
  var rePassword = req.body.rePassword;
  var email = req.body.email;
  /*
    1. 正则验证(-)
    2. 密码和确认密码是否一致
    3. 去数据库中查找有无此用户名
    4. 插入数据
   */
  //判断密码和确认密码是否一致
  if (password !== rePassword) {
    res.send('两次密码输入不一致,请重新输入~~');
    return
  }
  //去数据库中查找有无此用户名
  Users.findOne({username: username}, function (err, data) {
    if (!err) {
      /*
        data
          如果查到了  返回文档对象
          如果没找到  返回null
       */
      if (data) {
        // 查到了指定用户名
        res.send(data.username + '用户名已被注册~~请重新输入');
      } else {
        // 没有找到指定有户名,将用户信息插入到数据库中
        Users.create({
          username: username,
          password: password,
          email: email
        }, function (err) {
          if (!err) {
            res.send('恭喜您,注册成功了~~');
          } else {
            res.send('error');
          }
        })
      }
    } else {
      res.send('error');
    }
  })
})
//暴露路由器对象
module.exports = router

25、EJS模板

EJS是一个高效的 JavaScript 模板引擎。模板引擎是为了使用户界面与业务数据(内容)分离而产生的。

简单来说,使用EJS模板引擎就能动态渲染数据。

25.1、EJS的使用

  1. 下载安装

    npm i ejs --save

  2. 配置模板引擎

    app.set("view engine" , "ejs");

  3. 配置模板的存放目录

    app.set("views","./views")

  4. 在views目录下创建模板文件

    xxx.ejs

  5. 使用模板,通过response来渲染模板

    response.render(‘模板名称’, 数据对象)

25.2、EJS语法

以下是一个ejs文件

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body><h1>Hello EJS,这是我的第一个EJS</h1>
    
//<% code %> 执行其中的JS代码
<% console.log("Hello EJS"); var a = 30; %>
​
//<%=username%> 输出转义的数据到模板上
<h2>用户名 : <%=username%></h2>
    
//<%-username%> 输出非转义的数据到模板上
<h2>用户名 : <%-username%></h2>
​
//<% %> 可以包含JS代码与下面拼接在一起
<% if(a==20){ %>
<h3>a的值是20</h3>
<% } %>
<% for(var i=0 ; i<3 ; i++){ %>
<h3>老师真帅啊!!!!!</h3>
<% } %>
</body>
</html>

26、会话控制

HTTP协议是一个无状态的协议,它无法区分多次请求是否发送自同一客户端。

而我们在实际的使用中,却又大量的这种需求,我们需要通过会话的控制来解决该问题。

26.1、cookie

cookie本质是一个存储在浏览器的文本,随着http请求自动传递给服务器。

也可以说cookie是一个头(请求头/响应头):

  • 服务器以响应头的形式将Cookie发送给浏览器
  • 浏览器收到以后会自动将Cookie保存
  • 浏览器再次访问服务器时,会以请求头的形式将Cookie发回
  • 服务器就可以通过检查浏览器发回的Cookie来识别出不同的浏览器
26.1.1、cookie的不足
  • 各个浏览器对cookie的数量和大小都有不同的限制,这样就导致我们不能在Cookie中保存过多的信息。一般数量不超过50个,单个大小不超过4kb。
  • cookie是由服务器发送给浏览器,再由浏览器将cookie发回,如果cookie较大会导致发送速度非常慢,降低用户的体验。
26.1.2、 cookie的使用

通过配置cookie-parser中间件,可以将cookie解析为一个对象,并且添加为req的cookies属性,使用步骤:

  1. 下载安装

    npm i cookie-parser --save
    
  2. 引入

    var cookieParser = require("cookie-parser");
    
  3. 设置为中间件

    app.use(cookieParser());
    
  4. 创建Cookie

    res.cookie("username","sunwukong" , {maxAge:15000});
    
    //设置一个有效期为1天的cookie
    res.cookie("username","sunwukong" , {maxAge:1000*60*60*24});
    //设置一个永久有效的cookie
    res.cookie("username","sunwukong" , {maxAge:1000*60*60*24*365*10});
    
  5. 修改Cookie

    //Cookie一旦发送给浏览器,就不能再修改了
    	//但是我们可以使用同名的cookie来替换已有cookie
    res.cookie("username","zhubajie");
    
  6. 删除Cookie

    //可以通过通过使用一个立即失效的cookie来替换cookie的形式来删除cookie
    res.cookie("username","11",{maxAge:0});
    //用来删除一个cookie
    res.clearCookie(“username”)用来删除一个指定cookie
    

26.2、session

Session是一个对象,存储特定用户会话所需的属性及配置信息。

26.2.1、session运作流程

我们可以在服务器中为每一次会话创建一个对象,然后每个对象都设置一个唯一的id,并将该id以cookie的形式发送给浏览器,然后将会话中产生的数据统一保存到这个对象中,这样我们就可以将用户的数据全都保存到服务器中,而不需要保存到客户端,客户端只需要保存一个id即可

26.2.2、session的使用
  1. 下载安装

    npm i connect-mongo express-session --save
    
  2. 引入模块

    var session = require("express-session");
    
  3. 设置为中间件

    app.use(session({
      name: 'id22',   //设置cookie的name,默认值是:connect.sid
      secret: 'atguigu', //参与加密的字符串(又称签名)
      saveUninitialized: false, //是否为每次请求都设置一个cookie用来存储session的id
      resave: true ,//是否在每次请求时重新保存session
      cookie: {
        httpOnly: true, // 开启后前端无法通过 JS 操作
        maxAge: 1000*30 // 这一条 是控制 sessionID 的过期时间的!!!
      },
    }));
    

26.3、cookie和session的区别

  1. 存在的位置

    • cookie 存在于客户端,临时文件夹中
    • session 存在于服务器的内存中,一个session域对象为一个用户浏览器服务
  2. 安全性

    • cookie是以明文的方式存放在客户端的,安全性低,可以通过一个加密算法进行加密后存放
    • session存放于服务器的内存中,所以安全性好
  3. 网络传输量

    • cookie会传递消息给服务器
    • session本身存放于服务器,但是通过cookie传递id,会有少量的传送流量
  4. 生命周期(以20分钟为例)

    • cookie的生命周期是累计的,从创建时,就开始计时,20分钟后,cookie生命周期结束。(带有时效性的 cookie, 关闭浏览器不会销毁此 cookie。不带时效性的 cookie, 关闭浏览器就会销毁, 如果不关闭浏览器, 此 cookie 就一直有效)
    • session的生命周期是间隔的,从创建时,开始计时如在20分钟,没有访问session,那么session生命周期被销毁;但是,如果在20分钟内(如在第19分钟时)访问过session,那么,将重新计算session的生命周期;关机会造成session生命周期的结束,但是对cookie没有影响
  5. 大小

    • cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存50个cookie
    • session保存数据理论上没有任何限制(内存有多大就能有多大)