HTTP请求报文
一个HTTP请求报文有 请求行、请求头、空行和请求数据 这几部分组成
请求行 有请求方法、url和http协议版本字段 3个组成
HTTP协议请求方法有 get、post、head、put、delete、options、trace、connect
请求头 由 关键字/值对组成,每行一对, 关键字和值用英文冒号":"分隔, 请求头部通知服务器有关于客户端请求的信息
空行 最后一个请求头之后是一个空行, 发送回车符和换行符, 通知服务器一下不在有请求头
请求数据不在 get 方法中使用, 而是在 post 方法中使用, post 方法适用于需要客户填写表单的场合, 与请求数据相关的最常使用的请求头是 Content-Type 和 Content-Length
 
响应报文
http 响应也由三部分组成, 分别是: 状态行, 消息报头,响应正文.
状态行: HTTP/1.1(响应采用的协议和版本号) 200(状态码) OK (描述信息)
消息报头: 有 关键字/值对组成, 每行一对, 关键字和值 用英文的冒号 ' : ' 分隔
响应正文:  HTML页面
 
 
 
node 文件路径  手动运行
nodemon 文件路径 自动运行
 location.href=’要跳转的网页’ 跳转到 ‘其他网页’
使用npm init -y 初始化包管理配置文件 (就是创建一个package.json)
运行 npm i express -S   安装node框架
module.exports 向外暴露私有成员
//创建服务器
const express = require('express');
const app = express();
__dirname 代表当前文件所在目录
//启动服务器
App.listen(端口号,()=>{});
//创建服务器
const express =require('express');
// 调用服务器
const app = express();
// 启动服务器
app.listen(5001,()=>{
console.log('http://127.0.0.1:5001')
});
cls 清空控制(终端)台
语言和环境(平台)之间的关系
  1. 语言,是编写代码的语法规范。程序员遵循特定的语法规范,编写出来的代码,只有单纯的文本字符串,并不具备可执行特点
  2. 环境(平台),提供了执行代码的能力,如果程序员编写的代码想要成功执行,必须要依赖于特定的执行环境
例如:JavaScript代码可以被浏览器中的JS解析引擎执行
所以,浏览器,就是一个JavaScript的执行环境;因为JavaScript代码可以在浏览器中被执行
 
前端与后端
  1. 前端主要工作
(1) 页面结构
(2) 美化页面样式
(3) 书写页面的业务逻辑
(4) 使用AJAX调用后台接口
  1. 后端主要工作
(1) 操作数据库
(2) 对外暴露操作数据库的API接口
  1. 前后端协作开发
 
什么是nodejs?
就是JavaScript的服务器端运行环境,可以让程序员使用JavaScript来实现服务器端的编程
 
node.js中Javascript的组成部分
① ECMAScript核心 + 全局成员 + 核心API模块
1) 全局成员:console、setInterval、setTimeout..........
2) 核心API模块:就是node平台单独提供的一些API,这些API是node平台所独有的
注意:node.js 中没有 BOM 和 DOM
  由于node服务器端运行环境中,没有浏览器和HTML 的概念,所以,node中的JavaScript提出了 BOM和DOM 这两个对象模型,取而代之,是全局成员 和 核心API模块
 
 
ECMAScript规范,浏览器中的JS ,node 中的JS 之间的关系
  1. ECMAScript规范(标准):就是一本书,这本书中规定了语言的特性,ES6规范、ES7规范
  2. 浏览器中的JS
① 浏览器中的JS组成部分:ECMAScript核心 + DOM + BOM
  1. Node中的JS
① node中的JS组成部分:ECMAScript核心 + 全局成员 + 核心API成员
1) ECMAScript核心 →指的就是ES6语法
 
 
学习node.js 可以做什么
node.js就是一个服务器的JavaScript编程符合规范的后端API 接口 或者 带后台功能的网站
   使用node.js 开发一些使用的工具 或者 包
   i5ting_toc 工具的作用,就是把 md文档,转换为HTML 网页(i5ting_toc -f 文件 【-f代表要转换的】)
运行 npm i i5ting_toc -g 全局安装这个工具
运行 i5ting_toc -f  文件名   进行文件的转换(转换成HTML页面)
基于 socket技术,开发类似于聊天室之类的即时通讯项目
基于electron环境 开发桌面软件  
 
俩个安装包的区别
LTS:是长期稳定版的安装包,运行稳定,安全【相对稳定】
Current:是最小特性版,这个安装包中有最新的node特性【学习和尝试使用 不太稳定】
 
什么是path环境
path环境变量的作用:能够让我们在终端中执行相关命令,从而快速启动应用程序
 
let(变量) 与const(常量)
之前定义变量,有var 关键字:有如下主要缺点:
存在变量提升问题,降低JS代码的可阅读性
没有 {} 块级作用域,容易造成变量污染
变量可以被多次重复定义
 
let主要特性:
不存在变量提升问题,只有定义之后才能使用此变量
{ } 作用域,而且,在同一作用域中,无法被重复定义,但是可以重新赋值
 
 const(常量)主要特性:
不存在变量提升问题,只有定义之后才能使用此变量
const 定义的常量 无法被重新赋值
当定义常量的时候,必须定义且初始化,否则报语法错误
const定义的常量,也有 块级作用域
可以直接通过 = 为常量对象中的属性赋值,但是无法直接使用 = 为常量重新赋值
 
 
变量的解构赋值
定义:所谓的解构赋值,就是把某个对象中的属性,当做变量,给解放出来,这样,今后就能够当做变量直接使用
可以使用 :  为解构出来的变量重命名
例如:
 // 变量的解构赋值
  const { name : name123, age, gender } = person
  console.log(name123)
 
箭头函数
把方法定义为箭头函数
(形参列表)=>{函数体代码}
 
箭头函数,本质上就是一个匿名函数
箭头函数的特性:箭头函数内部的this 永远和箭头函数外部的this保持一致
 
变体:
(1) 变体1:如果箭头函数,左侧的形参列表中,只有一个参数,则 左侧的小括号可以省略
(2) 变体2:如果右侧函数体中,只有一行代码, 则 右侧的{ } 可以省略
(3) 变体3:如果箭头函数左侧只有一个形参,且右侧只有一行代码,则两边的() 和{ } 都可以省略
注意:如果我们省略了右侧函数体的{ } ,那么,默认会把右侧函数体中的代码的执行结果,当做箭头函数的调用结果 直接return 出去, 所以不用自己手动  [return 会报错]
 
对象中的定义方法和定义属性
fs模块提供了一些API,用于以一种类似标准POSIX函数的方法与文件系统进行交互
使用require方法 导入fs模块
fs文件夹系统模块的作用就是来操作文件的
const fs = require('fs');
所有的文件系统操作都有异步与同步两种形式
异步形式的最后一个参数都是完成时回调函数,传给回调函数的参数取决于具体方法,但回调函数的第一个参数都会给异常,如果操作成功完成,则第一个参数是null或者undefined
err.message  //错误[标志]信息,错误报文;(错误原因)
 
文件读取:fs.readFile()
接收三个参数:
// 参数1:【必选参数】字符串的文件路径;表示要读取哪个文件
// 参数2:【可选参数】字符串类型的编码格式(utf-8),默认为 null
// 参数3:【必选参数】callback回调函数,有两个形参 ①err 错误的结果  ②data 读取到的内容
// 代码:
fs.readFile('文件名','utf-8',(err, data) => {
// 如果读取文件成功,则 err 为 null, data 是成功之后的数据
// 如果读取失败,则 err 为一个错误对象, data 为 undefined
// err 是Error类型的一个对象
// err.message  //错误信息,错误报文;(错误原因)
 console.log(err) // null
 console.log(data) // <Buffer 文件内容>
// Buffer 是二进制的数据,只不过在展示的时候,为方便展示,操作系统帮我们把二进制的Buffer转换为了16进制的格式
 })
 
 
文件写入:fs.weiteFile()
// 参数1: 要把文件写入到哪个路径中(文件名或者文件描述符)
// 参数2: 要写入的内容
// 参数3: 编码格式
// 参数4:回调函数 只有一个形参err
// 异步的写入数据到文件,如果文件已经存在,则覆盖文件,data可以是字符串或者buffer
// 如果data是一个buffer,则encoding 选项无效
代码:
fs.writeFile('./files/2.txt', '666','utf-8', err => {
if (err) return console.log('写入文件失败!' + err.message)
console.log('写入文件成功!')
})
 
文件追加:fs.appendFile()
参数1:要往哪个文件追加内容
参数2:要追加的内容
参数3:(可选)要以什么编码格式追加进去 默认utf-8
参数4:回调函数 err(错误信息)
fs.appendFile('01-nodejs/1.txt','\n222','utf-8',err=>{
if (err) return console.log('追加失败:'+err.message);
console.log('追加成功')
})
 
异步的追加数据到一个文件,如果文件不存在则会创建这个文件,不会报错
 
 
fs模块中路径操作问题
使用fs模块操作文件的时候,如果提供的操作路径是 相对路径 ,则会根据当前执行node 命令是的磁盘目录,去拼接提供的文件相对路径,从而容易出现问题
注意:在调用 fs 相关的方法的时候,如果提供的操作路径是相对路径,那么很容易出现路径问题,在操作文件的时候 会直接以当前运行node 命令是,所在的路径来拼接用户提供的相对路径
解决方法:在操作文件的时候,提供相对路径
推荐使用node中提供的__dirname 来解决fs模块操作文件时候的路径问题
__dirname 代表当前文件所在目录
__filename 代表当前文件的文件名(代表当前文件所在目录和文件名)
 
 
 
读取文件信息 fs.stat (不是文件内容)
参数1:要读取那个文件(文件名)
参数2:
参数3:回调函数 有俩个形参 一个是err 错误信息  一个是stats 读取成功的信息对象(有文件大小、文件的创建时间、还有方法......等等可以查文档有详细的说明)
代码:↓
fs.stat(__dirname + '文件夹名',(err,stats)=>{
if(err) return console.log('读取文件失败'+ err.message)
console.log(stats.size) // 读取文件大小(不能直接获取目录大小) 单位是 字节 Byte
console.log(stats.birthtime) // 文件创建时间
......等等
console.log(stats.isFile()) // 方法: 判断是否是一个文件
console.log(stats.isDirectory())  // 判断是否是一个目录
......等等
})
读取指定目录下所有文件的名称 fs.readdir()
参数1:要读取那个路径
参数2:
参数3:回调函数(读取的结果) 有俩个形参 err 错误信息  files [数组] 代表读取到的所有文件的文件名
异步的readdir(3)。读取一个目录的内容,回调有俩个参数(err,files),其中files是目录中不包'.'和'..'的文件名的数组
可选的options参数用于传入回调的文件夹名,他可以是一个字符串并指定一个字符编码,或者一个对象且有一个encoding属性指定使用的字符编码。如果encoding设置'buffer',则返回的文件名会被作为buffer对象传入,注意:'path'的路径是以前文件为基准进行查找的,而不是运行的时候的相对路径
 
 
 
复制文件 fs.copyFile()
参数1:要被拷贝的源文件名称
参数2:拷贝操作的目标文件名
参数3:(可选)拷贝操作修饰符 默认0
参数4:回调函数 一个形参 err 错误对象
异步的将 src 拷贝到 destAsynchronously copies src to dest. 默认情况下,如果 dest 已经存在会被覆盖。回调函数没有给出除了异常以外的参数。Node.js 不能保证拷贝操作的原子性。如果目标文件打开后出现错误,Node.js 将尝试删除它。
flags 是一个可选的整数,用于指定行为的拷贝操作。唯一支持的 flag 是 fs.constants.COPYFILE_EXCL ,如果 dest 已经存在,则会导致拷贝操作失败。
 
 
路径操作
首先导入模块
path 模块提供了一些工具函数,用于处理文件与目录的路径。可以通过以下方式使用:
const path = require('path')
path.join() 只要涉及到路径片段的拼接一定要使用path.join()方法,尤其是读取文件的时候
可以解决路径问题 只要涉及到查找上一层目录的文件 就必须用path.join()方法 不可以使用 ../ 的方法
 
path.sep
提供了平台特定的路径片段分隔符
  • Windows 上是 \
  • POSIX 上是 /
path.basename(path[,ext]) 获取文件名,不包含文件路径
EXT是延伸文件系统(英语:Extended file system,缩写为 ext或 ext1),译为扩展文件系统,一种文件系统,
方法返回一个 path 的最后一部分,类似于 Unix 中的 basename 命令。 没有尾部文件分隔符,请查阅path.sep
path.basename('/foo/bar/baz/asdf/quux.html');// 返回: 'quux.html'
 
path.basename('/foo/bar/baz/asdf/quux.html', '.html');// 返回: 'quux'
如果 path 不是一个字符串或提供了 ext 但不是一个字符串,则抛出 TypeError
 
path.dirname(path)获取文件所处路径,不包含文件名
path.extname(path) 获取文件扩展名
 
 
 
JavaScript的单线程和异步
JavaScript的解析和执行一直是 单线程的,但是 宿主环境(浏览器或者node)是多线程的
异步任务是有宿主环境开启子线程完成,并通过事件驱动 回调函数 队列,把完成的任务,交给主线程执行
JavaScript借新引擎,一直在做一个工作,就是从任务队列里提取任务,放到主线程里执行
 
Node中的API为什么几乎都是异步操作
  1. 什么样的操作需要使用异步处理:要把耗时的操作,放到异步中去执行
  2. 异步执行任务的好处:能够提高耗时的任务他的执行效率,提高JS解析引擎的工作效率
 
认识模块化
模块化就是一种约定,一定规范
场景模拟:三个人共同基于node.js开发项目
  1. 为什么要有模块化:为了解决文件之间的依赖关系
  2. 注意:模块化是一种开发思想:具体开发中需要定制符合实际需求的模块化规范
  3. 大家可以把模块化规范,认为是一种文明的约定,大家都按照相同的约定写代码,减少了不必要的沟通成本,极大方便课各个模块之间的调用,方便别人,同时也方便自己
 
 
了解commonJS规范
  1. 作用:是一套JavaScript的模块化规范,规定了模块化的特性和各模块之间如何相互依赖
  2. 用途:node.js中使用可commonJS规范
  3. 特点:同步加载模块,不适合在浏览器使用
  4. CommonJS规范都定义了哪些内容:wiki对于Modules的描述
每个模块中,都应该有exports ,作用:是把当前模块中的成员暴露出去,给别人使用
module就代表当前这个模块
module.require是用来导入其他模块的
 
node中,每一个JS文件,大家都可以把他认为是一个模块
 
 
CommonJS规范中,每一个模块,都有自己独立的作用域
默认情况下,外界导入当前模块之后,无法直接访问当前模块中的成员
因为 模块中的成员 ,默认都是私有的
在浏览器中,如果定义一个变量,这个变量默认属于全局window作用域
但是,在node如果模块中定义一个变量,默认 不属于全局global作用域
 
在今后开发中,不要使用global作用域,会存在变量污染问题
 
模块作用域和全局作用域
node.js中有两个作用域,分别是全局作用域和模块作用域
  1. 全局作用域使用global 来访问,类似于 浏览器中的window
  2. 每个JavaScript文件,都是一个单独模块,每个模块都有自己独立的作用域,因此 模块中的成员,默认无法被其他模块访问
 
 
模块作用域
  1. module(模块标识)
module属性是CommonJS 规范中定义的,他是一个对象,表示当前这个具体的JS 模块
  1. require(引用模块)
每一个实现了CommonJS规范的模块,必须定义一个require()函数,使用这个require函数,就能够很方便的导入其他模块中的成员供自己使用
  1. exports(暴露模块成员)
每一个模块中,如果想要把自己的一些私有成员,暴露给别人使用,那么 必须实现一个exports对象,通过exports对象,可以方便的把模块内私有的成员,暴露给外界使用
 
module.exportsexports的关系
  1. module.exports和exports默认引用了同一个空对象
  2. module.exports和exports作用一致,都是可以向外暴露成员
  3. 一个模块作用域中,向外暴露私有成员时,永远以module.exports为准
 
浏览器端的AMD和CMD模块化规范
 
注意:浏览器端不能使用 CommonJS规范;因为 CommonJS 下,模块是同步加载的;
AMD/CMD可以理解为是commonjs在浏览器端的解决方案,AMD/CMD下,模块都是异步加载的;
AMD模块化规范代表:RequireJS
主要特性1:对于依赖的模块,AMD 是提前执行;
主要特性2:推崇依赖前置;
CMD模块化规范代表:SeaJS
主要特性1:对于依赖的模块,CMD 是延迟执行;CMD 推崇 as lazy as possible.
主要特性2:推崇依赖就近;
ES6的模块化(大趋势):es6是在语言标准层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案;
 
模块成员的分类
模块成员,根据一些区别又分为三大类:核心模块、第三方模块、用户自定义模块
 
核心模块
(1) 随着node.js的安装包,一同安装到本地的模块,叫核心模块
(2) 例如:fs,path等模块,都是由node.js官方提供的核心模块
(3) 只要大家在计算机中,安装了node 这个应用程序,那么 我们的计算机中就已经安装可所有的核心模块
(4) 使用核心模块:require('核心模块标识符')
第三方模块
(1) 一些非官方提供的模块,叫做第三方模块
(2) 注意:第三方模块,并不在我们计算机上
(3) 如果大家需要使用某个第三方模块,必须去一个叫npm 的网站上搜索并下载才能使用
使用第三方模块
(1) 先从npm 官网上下载指定的第三方模块
(2) 使用require('第三方模块的名称标识符')来导入这个模块
(3) 根据第三方模块的 官方文档 尝试使用
 
自定义模块
程序员在自己项目中写的JavaScript文件,就叫做自定义模块
使用自定义模块:require('路径标识符')
 
规范的包结构
  1. 包都要以一个单独的目录而存在
  2. package.json 必须在包的顶层目录下
  3. pachage.json 文件必须符合JSON格式,并且必须包含三个属性:name version main
(1) name :包的名字
(2) version: 包的版本号
(3) main:表示包的入口文件
  1. 二进制文件应该在bin目录下
  2. JavaScript代码应该在lib目录下
  3. 文档应该在doc目录下
  4. 单元测试应该在test目录下
  5. Node.js 对包要求并没有那么严格,只要顶级目录下右package.json,并符合基本规范即可
 
包描述文件package.json
name:包的名称,必须是唯一
description:包的简要说明
version:符合语义化版本识别规范的版本字符串
keywords:关键字数据,通常用于搜索
maintainers:维护者数组,每个元素要包含name、email、web可选字段
contributors:贡献者数组,格式与maintainers相同。包的坐着应该是贡献者数据的第一个元素
bugs:提交bug的地址,可以是网址或者电子邮件地址
licenses:许可证数组,每个元素要包含type和url字段
repositories:仓库托管地址数组,每个元素要包含type、url和path字段
dependencies:包的依赖,一个关联数组,由包名称和版本号组成。
devDependencies:开发依赖项,表示一个包在开发期间用到的依赖项
 
 
npm的两层含义
  1. NPM是一个第三方模块的托管(官方)网站 指的就是https://www.npmjs.com/
  2. NPM是node的包管理工具(全名叫做Node Package Manager),在我们安装node的时候,就已经顺便也安装npm这个管理工具
 
 
安装和卸载本地包
  1. 本地包:跟着项目安装的包,叫做本地包:本地包都会被安装到node_modules目录下
  2. 注意:如果拿到一个空项目,必须在当前项目目录中,先运行 npm init 或者 npm init -y 命令,初始化一个package.josn的配置文件,否则包无法安装到本地项目中
  3. 安装本地包:运行 npm i 包名 --save 即可安装本地包,都安装到了当前项目的 node_modules目录下。如果用的是npm 5.X 的版本,可以不指定--save命令,如果用的是 npm 3.x 的版本,则需要手动指定--save
  4. package-lock.json文件中记录了曾经装过的包的下载地址,方便下次直接下载包,能够加快装包的速度,提升装包的体验
  5. 卸载本地包:使用 npm uninstall/remove 包名 -S/-D 即可卸载指定的本地包
 
 
其他常用命令
npm i 包名  -g   (全局安装)
  1. --save 的缩写是 -S
  2. --save-dev的缩写是-D
  3. install 的缩写是 i
  4. 注意:dependencies节点,表示项目上线部署时候需要的依赖项,devDependencies节点,表示项目在开发阶段需要的依赖项,但是当项目要部署上戏了,devDependencies节点的包,就不在需要了
  5. 注意:当使用 npm i 快速装包的时候,npm 会检查package.json文件中,所有的依赖项,然后都会为我们安装到项目中
  6. npm --production表示只安装dependencies节点下,记录的包,不安装devDependencies节点下的包,当项目上线了,才会使用--production命令
 
 
解决npm下载慢的问题
  1. 默认NPM 在下载包的时候,连接的是国外的服务器,所以有时候如果网速不是特别好,可能下载不下来包,此时,可以全局安装一个工具,叫 cnpm
  2. 安装cnpm:运行  npm i cnpm -g 即可
  3. 使用cnpm: 在安装包的时候,只要把npm 替换成cnpm即可
 
 
B/S交互模型
B/S:特指基于 浏览器(Browser)和服务器(Server)这种交互形式
服务器:在网络节点中,专门对外提供资源服务的一台电脑
客户端:在网络节点中,专门用来消费服务的一台电脑
HTTP协议的通信模型:请求  处理  响应 的过程
请求:由客户端发起请求
处理:由服务器端处理请求
响应:服务器端把处理的结果,通过网络发送给客户端
 
静态资源:服务器端只需要读取并直接大宋给客户端、不需要进一步处理的资源,叫做静态资源
动态资源:服务器端没有现成的资源,需要服务器端动态生成的资源 叫做 动态资源
 
 
创建最基本的web 服务器
首先引入http模块: const http = require('http')
创建服务器:使用 const server = http.createServer()创建服务器
绑定监听事件:通过 server.on('request',function(req,res){请求的处理函数})绑定事件 并指定处理函数  req 请求对象   res 响应对象
启动服务器:通过 server.listen(端口号,ID地址,启动成功的回调函数) 来启动服务器 例如:
server.listen(3000,'127.0.0.1',()=>{
console.log('server running at http://127.0.0.1:3000'); 
})
防止响应内容乱码问题
 通过 设置响应报文头的 Content-Type 来指定响应内容的编码类型,从而防止乱码(固定写法如下:)
res.writeHeader(200, {
'Content-Type': 'text/html; charset=utf-8'
})
结束当前响应,并发送一些数据到客户端 : res.end()
 
 
根据不同的URL返回不同的文本内容
使用req.url 获取客户端请求的URL地址
根据不同的URL返回不同的HTML页面
主要思路:使用fs模块 读取URL对应的HTML 页面内容,并使用 res.end响应给客户端即可
 
 
使用nodemon工具来自动启动web服务器
nodemon的作用:能够实时监听当前项目中文件的变化,只要监听到了文件的变化,则nodemon工具会自动重新启动nodemon服务器,从而使最小的代码生效,免去了程序员手动重启服务器的困扰
安装:运行 npm i nodemon -g 全局安装即可
使用:
之前使用node 要执行的文件路径 来运行node.js代码
现在使用 nodemon 要执行的文件路径 来运行node.js代码
注意:今后在开发web项目的时候,推荐使用 nodemon来启动web服务器
 
定义(什么是Express):一个快速的网站开发框架,封装了原生的http模块,用起来更方便,API更人性化
 
Express框架的特点
  1. 基于node.js平台之上,进一步封装了http模块,从而提供了更好用,更友好的API
  2. 使用express创建网站,比使用原生的http模块更加方便
  3. Express并没有覆盖原生http模块中的方法,而是基于原生方法之上,做了更友好的封装,让用户体验更好
 
Express框架的安装和基本使用
  1. 安装:npm i express -S
  2. 创建基本的express服务器
(1) 导入express第三方模块 const express = require('express')
(2) 创建服务器的实例:调用 const app = express()方法
(3) 通过app.get() 或者app.post()方法,来监听客户端的get或post请求 具体语法:
① 监听GET请求:app.get('请求地址',(req,res)=>{处理函数})
② 监听post请求:app.post('请求地址'(req,res)=>{处理函数})
1) 使用post()解决编码问题是 用querystring.parse(str[,sep[,eq[,options]]])【自动解码】
参数1:要解析的URL查询字符串
参数2:【可选】用于界定查询字符串的键值对的子字符串。默认‘&’
参数3:【可选】用于界定查询字符串中的键与值的子字符串。 默认为‘=’
参数4:【可选】
(4) 启动express服务器:通过app.listen(端口号,IP地址,启动成功的回调函数) 启动服务器
express中的快捷方法
  1. res.send()
(1) res.send()与res.end的区别:
① res.send()自带utf-8编码 不用自己在手动写入
(2) 支持发送字符串,[系统动态写入Content-Type:text/html]
① res.send('内容')
(3) 支持发送对象或者数组[系统动态写入 Content-Type:application/json]
① res.send({name:'张三',age:20}) 对象
② res.send([])数组
(4) 支持发送Buffer此时会当做文件下载(不会带上后缀名)
  1. res.sendFile()
(1) 用法1:res.sendFile(path.join(__dirname,'文件名'))
(2) 用法2:res.sendFile('文件名',{root:__dirname})
(3) 也支持下载文件(会自动带上后缀名)
① res.sendFile('要下载的文件',{root:__dirname,headers:{
'Content-Disposition':'attachment;filename= 文件名.后缀名'
}}) // Content-Disposition 指定文件类型  filename文件名
注意res.sendFile()可以向浏览器发送 静态页面
res.redirect(要跳转的路径) // 跳转到指定页面
res.render(模板页面路径,{ /*数据对象*/ })
下载文件
app.get('/',(req,res)={
res.download('要下载的文件名','自己改的文件名'err=>{
if(err) return console.log(); // 失败
console.log()// 成功
})
})
使用express.static() 快速托管静态资源
如果我们在网站中,有很多静态资源需要被外界访问,此时,使用res.sendFile就有点力不从心;
这时候,express框架,为我们提供了 express.static('静态资源目录') 来快速托管指定目录下的所有静态资源文件
语法1:app.use(express.static('资源目录'))
app.use()方法,值专门用来注册 中间件;
express.static是express的内置中间件
语法2:app.use('/虚拟目录',express.tatic('资源目录'))
 
 
express框架配置模板引擎渲染动态页面
  1. 安装ejs 模板引擎 npm i ejs -s
  2. 使用app.set()配置默认的模板引擎app.set('view engine','ejs')
  3. 使用app.set()配置默认模板页面的存放路径 app.set('views','要存放到哪个文件目录下')
  4. 使用res.render()来渲染模板页面 res.render(‘index.ejs’,{要渲染的数据对象}),注意,模板页面的后缀名,可以省略不写。(最好还是写上)
(1) 第一个参数:要渲染的页面名称→index.ejs
(2) 第二个参数:要渲染的内容 {} 里的内容
(3) 如果渲染的内容里有标签 只要把<%= %>改成<%- %>就可以了
这个模板只有 <%%> 没有 {{}} 的方法
可以省略不写
 
express中配置art-template
  1. 安装两个包 cnpm i art-template express-art-template -S
  2. 自定义一个模板引擎 app.engine('自定义模板引擎的名称',渲染函数)
(1) app.engine('html',require('express-art-template'))推荐使用这个
  1. 将自定义的模板引擎,配置为express的默认模板引擎 app.set('view engine','具体模板引擎的名称')
  2. 配置 模板页面的存放路径 app.set('views','路径')
 
使用express框架中提供的路由来分发请求
1.路由:就是对应关系
2.后端路由:前段请求的URL地址,都要对应一个后端的处理函数,那么 这种URL地址到处理函数之间的对应关系,就叫后段路由
3.在express中,路由注意职责 就是 把请求分发到对应的处理函数中
4.在express中定义并使用路由
   // 1. 封装单独的 router.js 路由模块文件
   const express = require('express')
   // 创建路由对象
   const router = express.Router()
挂载路由规则
   router.get('/', (req, res)=>{})
   router.get('/movie', (req, res)=>{})
   router.get('/about', (req, res)=>{})
   // 路由对象暴露出去
   module.exports = router
5.express创建的app服务器,使用路由模块
   // 导入自己的路由模块
   const router = require('./router.js')
   // 使用 app.use() 来注册路由
   app.use(router)
 
'路由:就是对应关系就是匹配规则
路由不会自己想当然的自我调用,而是由客户端请求到达服务器之后,拿着客户端请求的method类型,请求的URL地址,来和后端的路由规则,进行逐条匹配
如果匹配成功,则立即调用路由规则中指定的出路函数,使用指定的处理函数 来处理和响应这次请求
后端路由由三部分组成,分别是​:请求类型(Method) ,请求地址(URL), 处理函数(就是路由规则中的回调函数)
对于路由来说,路由的主要职责:就是把客户端的请求,分发到对应的处理函数中
注意:对于路由来说,只关心分发请求的过程,不关心处理函数中具体的业务实现逻辑;'
 
 
mysql第三方模块基本配置
 
  1. 要安装操作数据库的第三方包 npm i mysql -S
  2. 导入包 const mysql = require('mysql')
  3. 创建数据库连接对象
const conn = mysql.createConnection({
  host: '127.0.0.1', // 要连接到哪个电脑上的数据库  
user: 'root', // 登录数据库的用户名  
password: 'root', // 登录数据库的密码  
database: 'heima_47' // 指定当前这个数据库连接对象,要操作哪个数据库})
 
4.使用conn.query('要知晓得sql语句'要提供的数据,(err,reslt)=>{回调函数}) 来执行sql语句
// result 执行的结果
// err 错误对象
// 查询数据
conn.query('要执行的Sql语句', 回调函数)
const sql1 = 'select * from users'
conn.query(sql1, (err, result) => {
// 如果执行Sql语句失败,则 打印报错信息
if (err) return console.log(err.message)
console.log(result)
})
 
//添加数据
const user = { username: '小绿', address: '日本' }
const sql = 'insert into users set ?'
conn.query(sql, user, (err, result) => {
if (err) return console.log(err.message)
console.log(result)
})
 
 
//修改数据
const user = { id: 4, username: '老驴', address: '小日本儿' }
const sql = 'update users set ? where id=?'
conn.query(sql, [user, user.id], (err, result) => {
if (err) return console.log(err.message)
console.log(result)
})
 
//删除数据
const sql = 'delete from users where id=?'
conn.query(sql, 4, (err, result) => {
if (err) return console.log(err.message)
console.log(result)
})
 
 
'中间件
定义:中间件就是一个处理函数; 只不过这个函数比较特殊,包含三个参数,分别是 req、res、next
注意:中间件方法中的三个参数是:
req: 请求对象  res:相应对象  next:next()可以被调用,表示调用下一个中间件方法
 
每个流水线上的数据,都可以叫’中间件’  这些数据就是中间件的操作对象
中间件之间会共享一些数据   
每个中间件,只负责做一件事情,功能单一
中间件之间,可以进行顺序的调用
如果上一个中间件,没有吧操作的结果,放回流水线,则下一个中间件,就无法继续进行操作了
 
Express框架中对中间件的5种分类
  1. 应用级别的中间件:挂在到app上的中间件 app.get('URL地址',(req,res,next)=>{})
  2. 路由级别的中间件:挂在到router对象上的中间件 router.get('URL地址',(req,req,next)=>{})
  3. 错误级别的中间件:回调函数中,有四个参数app.use((err,req,res,next)=>{})
  4. 唯一内置的中间件:express.static() // 托管静态资源
  5. 第三方中间件:非express框架提供的,需要程序员手动安装才能使用的中间件,body-parser 解析post表单数据
 
 
模块加载机制
优先从缓存中加载
当一个模块初次被require的时候,会执行模块中的代码,当第二次加载相同模块的时候,会优先从缓存中查找,看有没有这样的一个模块
好处: 提高模块的加载速度,不需要每次都重新执行并加载模块
 
核心模块的加载机制
线查找缓存
如果缓存中没有则尝试加载永辉模块
如果在加载用户模块的时候省略后缀名 :
  1. 首先,严格按照指定的名称去查
  2. 其次,尝试加载后缀名是 .js的文件
  3. 如果没有 .js的文件,则尝试加载 .json结尾的文件
  4. 如果没有 .json的文件,则尝试加载 .node结尾的文件
  5. 查找规则: index ->index.js ->index.json ->index.node
 
第三模块的加载机制
  1. 先在当前模块的父目录中,查找 node_modules 文件
  2. 在node_modules文件夹下,查找模块相关的文件夹
  3. 在对应的文件夹下,查找package.json的文件
  4. 查找package.json文件中的main属性(指定了模块的入口文件)
  5. 如果找到了main属性,同时,main属性指定的文件路径存在,那么尝试加载main属性指向的模块,直到加载成功为止;
  6. 假如main属性指向的文件不存在,则直接报错:Error:Cannot find module ***
  7. 假如没有main属性,或者没有package.json,那么会依次尝试加载index.js,index.json, index.node;
  8. 如果没有index相关的文件,或node_modules中,没有模块名称对应的文件夹,或者,当前项目根目录中没有node_modules文件夹,则向上一层目录中查找node_modules,查找规则同上!
  9. 最后,如果在项目所在磁盘的盘符根目录中,还找不到对应模块,则报错:cannot find module ***
 

. express中获取参数的几种形式

获取 http://127.0.0.1:3001/user?id=10&name=zs 中的查询参数:
直接使用 req.query 获取参数即可;
注意:URL 地址栏中通过 查询字符串 传递的参数,express 框架会直接解析,大家只需使用 req.query 直接获取 URL 中 查询字符串的参数;
URL地址中获取路径参数:
假设客户端浏览器请求的URL地址为:http://127.0.0.1:3001/user/10/zs
假设后台的路由是 app.get('/user/:id/:name', (req, res) => {})
直接使用 req.params 可以获取URL地址中传递过来的参数;
post表单中获取提交的数据:
借助于body-parser来解析表单数据
安装:npm i body-parser -S
导入:const bodyParser = require('body-parser')
注册中间件:app.use(bodyParser.urlencoded({ extended: false }))
使用解析的数据: req.body 来访问解析出来的数据
 
 
 

2.1 混合模式(传统开发模式)

以后端程序员为主,基本上不需要前端程序员,或者,前端程序员只负责画页面、美化样式、写JS特效,前端程序员不需要进行数据的交互;
这种开发模式,在早些年比较常见;
传统开发模式下,用的最多的是 Jquery + 模板引擎 + Bootstrap
后端页面 .php .jsp .aspx .cshtml

2.2 前后端分离(趋势)

后端负责操作数据库、给前端暴露接口
前后端分离的好处:保证了各个岗位的职责单一;
前端负责调用接口,渲染页面、前端就可以使用一些流行的前端框架 Vue, React, Angular
前端页面的后缀名 .html .vue .jsx
 
 

JSONP 和 CORS 的区别

JSONP的原理:动态创建script标签;
JSONP发送的不是Ajax请求
不支持 Post 请求,只支持 Get 请求;
CORS中文意思是跨域资源共享 ,需要服务器端进行 CORS 配置;
CORS 发送的是真正的Ajax请求
CORS 支持Ajax的跨域
如果要启用 CORS 跨域资源共享,关键在于 服务器端,只要 服务器支持CORS跨域资源共享,则 浏览器肯定能够正常访问 这种 CORS 接口;而且,客户端在 发送 Ajax的时候,就像发送普通AJax一样,没有任何代码上的变化;
对于Node来说,如果想要开启 CORS 跨域通信,只需要安装cors的模块即可;
 
'MVC:就是分层开发的思想;
把复杂的业务处理,分为职能单一的小模块,各个模块之间看似相互独立,其实又各自有依赖关系
MVC的好处:保证了模块职能的单一性,方便程序的开发、维护、拓展
MVC中,M代表Model 是数据库操作层, V代表View,是页面视图层 C代表Controller,是业务处理层
注意: 在MVC分层开发思想中,Controller业务逻辑层,是最重要的一部分;
 
 
 
module.exports把文件暴露出去
URL解码
decodeURL(要解码的内容)
URL编码
encodeURL(要编码的内容)