NODE.JS

NODE.JS

什么是node.js?

  • Node.js® is a JavaScript runtime(运行时、运行环境) built on Chrome's V8 JavaScript engine.

    • Node.js 是一个构建于 Chrome V8 引擎的 JavaScript 运行环境。

    • Node.js 为 JavaScript 代码的正常运行,提供的必要的环境。

    • 不是库、框架、不是语言。

    • 是一个JS运行时环境。简单说就是可以解析和执行JS代码。

    • 像浏览器一样提供可以解析和执行的环境,但不是浏览器。以前只有浏览器可以解析和执行js代码,有了node.js,现在可以脱离浏览器去解析和执行。

    (技术性的网站一般都是io或者org)

  • 浏览器中的javaScript:
    • ECMAScript(语法)

      • 基本的语法

      • if语句

      • var

      • function

      • objeck

      • array

    • DOM

    • BOM

  • node.js中的javaScrip:
    • 没有DOM和BOM。(服务端不负责处理处理DOM和BOM)

    • 有ECMAScript

    • 在node这个JavaScript执行环境中为JavaScript提供了一些操作服务器级别的API。如:

      • 文件的读写

      • 网络服务的构建

      • 数据网络通信

      • http服务器。。。

  • node.js 的特点
    • 单线程,非阻塞I/O,事件驱动。

    • 相比多线程语言更节省内存,非阻塞I/O使得程序不停在运行,事件驱动可以处理I/O后的回调。

    • 单线程则系统不会再用于建立销毁线程增加开销,不过线程出问题,全部业务都出问题。

    • 在非阻塞模式下,一个线程永远在计算,线程CPU核心利用率永远100%。

  • npm是最大的开源库生态系统。(node.js开发的)绝大多数的JavaScript相关的包都存放在npm上面,这样做的目的是为了使开发人员更方便的使用和下载。

Node.js能做什么

  • web服务器后台,网站后台

  • 命令行工具

    • npm

    • git(c语言开发的)

    • hexo(node开发的)

  • 对于前端开发工程师来说,接触node最多的是命令行工具,自己写的很少,主要是使用第三方工具

可以学到什么

  • B/S编程模型

    • Browser-server

    • back-end

    • 任何服务端奇数这种BS编程模型都是一样的,和语言无关

    • Node只是作为我们学习BS编程模型的一个工具

  • 模块化编程

    • RequireJS

    • SeaJS

    • 在Node中可以像@import('w文件路径')一样来引用加在JavaScript脚本文件

  • Node常用API

  • 异步编程

    • 回调函数

    • Promise

    • async

    • agenerator

  • ES6新语法

global模块

global模块,是node的全局模块,在使用时不需要引入,可以直接使用。


  * window 顶层对象 全局变量
  * global 全局模块 里面的变量 , 都是全局变量 
  * 注意 : node里面使用 global里面的变量,不需要引入 , 说明其他的是需要引入的
  */

  //1\. console.log()  打印
 ​
  //2\. setTimeout 和setInterval ,延时器和定时器
  setTimeout(() => {
  console.log('123');
  }, 1000);
 ​
  //3\. __dirname 当前文件夹的绝对路径
  //从当前所在磁盘盘符一直到当前文件夹的路径
  console.log(__dirname);

  //4\. require 引入模块 
  // 在node里是通过require 来引入模块的
  // 除了global其他模块都是需要引入的
  const fs = require('fs') 
 ​</pre>

Node中的JavaScript

  • EcmaScript

    • 没有DOM、BOM
  • 核心模块

核心模块

Node为JavaScript提供了很多服务器级别的API,这些API绝大多数都被包装到了一个具体的核心模块中了。例如操作文件的fs核心模块,http服务构建的http模块。。如果需要使用核心模块,就必须先引入const fs = require('fs')

fs 文件系统核心模块

fs是file-s 的简写,他是node.js提供的用来操作文件的模块。在fs这个核心模块中,就提供了所有文件操作相关的API。使用文件系统模块之前,先i引入fs模块:conts fs = require('fs')

(浏览器中的JavaScript没有文件操作的能力,node.js中有操作文件的能力)浏览器不认识node代码

  • 向指定文件读取内容:fs.readFile()

    • fs.readFile(path[, options], callback)

      • 参数1:必选,指定文件的路径

      • 参数2:可选,表示以什么编码格式读取

      • 参数3:必选,回调函数。

        • 第一个参数err(错误内容),读取成功会返回null。

        • 第二个data(读到的数据)

  • 向指定文件书写内容:fs.writeFile()

    • fs.writeFile(file, data[, options], callback)

      • 参数1:必选,指定文件的路径

      • 参数2:必选,要书写的文件内容

      • 参数3:可选,以什么格式写入,默认为'utf8'

      • 参数4:必选,回调函数。参数err(错误内容),读取成功会返回null

    【注】1、以覆盖的形式写入文件

    2、写入的文件不存在,会新创建一个文件

  • 读取指定目录下所有文件的名称:fs.readdir()

    • fs.readdir(path[, options], callback)

      • 参数1:必选,指定要读取哪个目录下所有的文件名称

      • 参数2:可选,以什么格式读取目录

      • 参数3:回调函数

path 路径核心模块

path 模块是 Node.js 官方提供的、用来处理路径的模块。使用之前需要先引入const path = require('path')

  • 路径拼接path.join()

    • path.join([...paths])

    • paths <string> 多个路径片段的序列,返回值string

    • 默认按照拼接顺序拼接

  • 获取路径中的文件名path.basename()

    可以从一个文件路径中,获取到文件的名称部分

    • path.basename(path[,ext])

    • path <string> 必选参数,表示一个路径的字符串

    • ext <string> 可选参数,表示可选的文件扩展名

    • 返回: <string> 表示路径中的最后一部分,如果不存在路径,全部都是文件名。路径存在,取最后一个斜杠后面的内容

http核心模块

http 模块是 Node.js 官方提供的、用来创建web 服务器和客户端的模块。使用之前需要先引入const http= require('http')

创建 web 服务器的基本步骤

  1. 导入http核心模块

  2. 使用http.creatServer()方法创建一个web服务器,返回一个Server实例

  3. 给Server实例绑定request 事件,监听客户端的请求。当客户端发送请求过来,会触发服务器的request请求事件,然后执行回调函数

  4. 绑定端口号,启动服务器(不要设置6666)

示例代码

// 1\. 加载 http 模块
 const http = require('http');
 // 2\. 创建server 对象
 const server = http.createServer();
 // 3\. 监听端口,开启服务器
 server.listen(3000, () => console.log('my server running'));
 // 4\. 注册server的request事件,准备处理浏览器的请求
 server.on('request', (req, res) => {
  // req request  请求,通过req对象可以获取到所有和请求相关的信息
  // res response 响应,通过res对象可以做出响应以及设置一些和响应相关的内容
 ​
  // // 设置响应头
  // res.setHeader('Content-Type', 'text/html; charset=utf-8');
  // res.setHeader('Author', 'zhangsan'); // 自己设置响应头,不要用中文
  // // 设置响应状态码
  // res.statusCode = 200;
 ​
  // 综合性的设置响应状态码和响应头的方法
  res.writeHead(200, {
  'Content-Type': 'text/html; charset=utf-8',
  'Author': 'zhangsan'
  });
  // write方法,也可以设置响应体,但是没有做出响应的意思,只是单纯的设置响应体
  res.write('1234');
  res.write('5678');
  // res.end(响应体); // 做出响应
  res.end('hello,你的请求我收到了');
  // 做出响应之后,不能再有其他代码。
 });</pre>

【注意】如果代码修改,要重启服务器才能

Request请求事件处理函数,需要接收两个参数,分别是Request请求对象和Response响应对象

Request 请求对象

可以用来获取客户端的一些请求信息,例如请求路径、方式、头、体,所有和请求相关的信息,都可以获取到。

  • 获取请求地址req.url

  • 获取请求方式req.method

Response 响应对象

可以用来给客户端响应消息。有一个方法res.write()可以用来给客户端发送响应的数据。write()方法可以使用多次,但最后一定要用end()结束响应,否则客户端会一直等待。可以在响应结束的时候,

  • 设置响应头,解决中文乱码

    • res.setHeader('Content-Type', 'text/html; charset=utf-8');
  • 设置状态码

    • res.statusCode = 200;
  • 综合设置响应头和状态码的方法

    • res.writeHead(200,{'Content-Type', 'text/html; charset=utf-8','Author':'ls'})
  • 响应体res.write()

    • 结束响应res.end()

【注】

  • 所有的请求路径 url 都是以 / 开头的

  • 响应内容只能是字符串或者二进制数据

当请求不同的路径的时候,响应不同的结果。

例如请求:

/ index ,响应index

/login,响应login

/haha,响应哈哈

server.on('request', (req, res) => {
 // 获取请求路径。再根据路径响应
  // 所有的请求路径 url 都是以 / 开头的
  var url = req.url
  if (url === '/index' || url === '/') {
  res.end('index page')
  } else if (url === '/login') {
  res.end('login page')
  } else if (url === '/haha') {
  res.end('haha page')
  } else {
  res.end('404 Not Found')
  }
 })</pre>

端口号

计算机中的端口号,就好像是现实生活中的门牌号一样。通过门牌号,外卖小哥可以在整栋大楼众多的房间中,准确把外卖 送到你的手中。

同样的道理,在一台服务器中,可以运行成百上千个web 服务。此时,通过端口号,客户端发送过来的网络请求,可以被准 确地交给端口号对应的web 服务进行处理。

npm初步使用

npm(node package manager)node包管理器。

包是什么?包就是模块。

npm这个工具,在安装node的时候,就已经安装到你的计算机中了。

命令行中执行: npm -v ,如果看到版本号,说明安装成功了。

作用

npm的作用是:管理node模块的工具。

  • 下载并安装第三方的模块

  • 卸载第三方模块

  • 发布模块

  • 删除已发布的模块

  • ....

npm 就是一个管理(下载安装、卸载...)第三方模块的工具

第三方模块:

  • 非内置模块,安装完node,还不能使用的模块,需要从网上下载安装,才能使用的模块

  • 第三方模块是个人、公司、组织编写的模块,发布到网上,供我们使用

初始化

使用npm工具之前,必须先初始化。

npm init -y

npm init

然后一路回车

初始化之后,会在项目目录中生成 package.json 的文件。

什么第三方模块

非node自带的模块。

是别人写的模块,然后发布到npm网站,我们可以使用npm工具来下载安装别人写的模块。

第三方模块,都是在node核心模块的基础之上,封装了一下,实现了很多非常方便快速简洁的方法。

目前,npm网站收录了超过 150万个第三方模块。

安装卸载项目模块

下载安装第三方模块

npm install 模块名
npm i 模块名

卸载模块

npm uninstall 模块名
npm un 模块名</pre>

安装指定版本:

npm i 模块名@版本号
npm i jquery@3.5.0</pre>

演示代码

这里演示一个处理时间日期的模块 -- moment

下载安装moment模块

npm init -y
npm i moment</pre>

演示使用moment模块处理时间

// 加载模块
const moment = require('moment');

console.log(moment().format('YYYY-MM-DD hh:mm:ss'));
// 官网:http://momentjs.cn</pre>

全局模块

  • 全局安装的模块,不能通过 require() 加载使用。

  • 全局安装的模块,一般都是命令或者工具。

  • 安装方法,在安装模块的命令后面,加 -g

npm i 模块名 -g
# 或
npm i -g 模块名</pre>

  • 卸载方法(也是多一个 -g

npm un 模块名 -g</pre>

  • 全局安装的模块,在系统盘(C盘)

    • 通过命令 npm root -g 可以查看全局安装路径
  • 查看安装的全局模块----没有-g查看本地安装,加上-g查看全局模块

npm list -g --depth 0

全局安装nodemon模块

  • 安装命令

npm i nodemon -g

  • nodemon的作用:

  • 代替node命令,启动服务的,当更改代码之后,nodemon会自动帮我们重启服务。

  • 运行nodemon,如果报错如下:

[图片上传失败...(image-2a0f9e-1609946235846)]

  • 解决办法是:

    • 管理员方式,打开命令行窗口

    • 执行 set-ExecutionPolicy RemoteSigned;

    • 在出现的选项中,输入 A,回车。即可

  • 执行 : nodemon 文件路径

更改镜像源

镜像源,就是下载安装第三方模块的网站。

我们下载的第三方模块都是从国外的npm主站下载的,速度比较慢。

淘宝在国内对npm上的第三方模块做了一个备份,也就是说,我们可以从国内下载第三方模块。

除了淘宝之外,还有很多其他镜像源。

简单的更改镜像源方法:

  • 全局安装 nrm 的模块

    • nrm 用于管理镜像源
  • 使用nrm

    • nrm ls 通过这个命令,可以查看可用的镜像源

    • nrm use taobao ,切换下载模块的网站为淘宝

模块化

模块化是指解决一个复杂问题时,自顶向下逐层把系统划分成若干模块的过程。 对于整个系统来说,模块是可组合、分解和更换的单元。

编程中的模块化

编程领域中的模块化,就是遵守固定的规则,把一个大文件拆成独立并互相依赖的多个小模块。

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

  • 提高了代码的复用性

  • 提高了代码的可维护性

  • 可以实现按需加载

  • 文件作用域

  • 通信规则

    • 加载require

    • 导出

Node中的模块分类:

Node.js 中根据模块来源的不同,将模块分为了 3 大类,分别是:

  • 内置模块(内置模块是由 Node.js 官方提供的,例如 fs、path、http 等)

  • 自定义模块(用户创建的每个 .js 文件,都是自定义模块)

  • 第三方模块(由第三方开发出来的模块,并非官方提供的内置模块,也不是用户创建的自定义模块,使用前需要先下载)

CommonJS规范

在node中的JavaScript有一个很重要的概念,系统模块

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

CommonJS 规定:

  1. 模块作用域

  2. 每个模块内部,module 变量代表当前模块。

  3. 使用require() 方法用于加载模块

  4. module 变量是一个对象,它的 exports 属性(即 module.exports)是对外的接口。使用exports接口对象导出模块中的成员

  5. 加载某个模块,其实是加载该模块的 module.exports 属性。

require加载自定义模块

语法演示:

// 加载自定义模块
const 自定义变量名 = require('./custom');</pre>

作用:

  • 执行被加载的模块中的代码

  • 得到被加载模块中的exports导出接口对象

注意事项

  • 加载自定义的模块,需要加 ./路径 ,而且可以省略后缀 .js

exports导出自定义模块

  • node中是模块作用域,默认文件中所有的成员只能在当前模块中有效,另一个JS文件就无法使用当前模块定义的内容所以需要导出导入文件

  • 每个模块内部都有一个module对象。在module对象中有一个成员叫exports,也是对象。谁require,谁就得到module.exports属性,默认是一个空对象。

  • 对于希望可以被其他模块访问的成员,只需要把成员挂载到module。使用 module.exports 导出需要共享的内容。

  • 导出等于是给其赋值,重复赋值会被覆盖。

  • 使用模块的JS文件需要使用 require() 导入模块。

  • 导入的内容就是,模块导出的内容

导出多个成员(必须在对象中)

exports.a = 123;
exports.b = 'hello';
exports.c = function(){
console.log('ccc')
}
exports.d = {
foo:'bar'
}</pre>

导出单个成员(拿到的就是函数、字符串)

module.exports = 'hello'

//以这个为准,后者会覆盖前者
module.exports = funciton(){
return x+y
}

//这样可以导出多个成员
module.exports{
add:function(){
return console.log(x+y)
},
str:'hello'
}</pre>

原理解析

  • 在node底层中,每个模块都有一个自己的module对象,该module对象中,有一个成员叫exports,也是一个对象

//演示:
var module= {
exports:{

}
}

//如果需要对外导出某些成员,只需要把这些成员挂载到module对象上的exports对象中。
module.exports.foo = 'bar'//等于是在exports对象中添加了 foo: 'bar'

//默认在代码的最后有一句,谁来require,谁就得到module.exports
return module.exports
</pre>

  • exports是module.exports的一个引用 var exports = module.exports

//我们发现,每次导出接口的成员的时候,都需要通过module.exports.xxx=xxx的方式很麻烦
//于是,node为了简化操作,专门提供一个变量 var exports = module.exports
console.log( exports === module.exports) //true 可以使用任何一方来导出接口成员

//二者等价.最后return的是 module.exports 所以注意不要给exports重新赋值
module.exports.foo = 'bar'//等于是在exports对象中添加了 foo: 'bar'
exports.foo = 'bar'</pre>

模块加载顺序和区别

通过引入的内容 核心模块和第三方模块直接引入模块名,自定义模块必须要带有路径。

// 加载核心模块
const fs = require('fs');
// 加载第三方模块
const express = require('express');
// 加载自定义模块
const custom = require('./custom');</pre>

加载顺序:

  • 无论是什么模块,我们都要使用 require() 去加载,然后才能使用。

  • 优先加载内置模块,即使有同名文件,也会优先使用内置模块

  • 不是内置模块,先去缓存中找,缓存没有去找对应路径的文件

  • 不存在对应的文件,就将这个路径作为文件夹加载。

  • 对应的文件和文件夹还找不到就去node_modules下面找

注意事项

  • 加载自定义的模块,需要加 require(./路径),可以省略文件扩展名

  • 加载第三方模块和核心模块。只需要写 require(模块名)

  • 如果是非路径形式的模块标识,会判断是不是核心模块,如果是,优先加载核心模块

  • 如果是路径形式的。肯定是第三方模块,会去当前的node_modules文件中查找

    • 优先加载相同名字的文件,加载一个叫做 abc 的文件

    • 自动补 .js 后缀,然后加载 abc.js 文件

    • 自动补 .json 后缀,然后加载 abc.json 文件

    • 自动补 .node 后缀,然后加载 abc.node 文件

    • 以上文件都没有,则报错 Cannot find module './abc'

其他

main说明

package.json文件中的main选项,作用时配置路口文件,在路口文件中坑定有导出(module.express)

如果没有main选项,那么项目根目录必然会有index.js,默认是入口文件。

依赖管理dependencies:

nodejs 中总共有 5 种依赖:

  • dependencies (常用)

  • devDependencies (常用)

  • peerDependencies (不太常用)

  • bundledDependencies (我之前没用过)

  • optionalDependencies (我之前没用过)

dependencies:

保存本地安装的所有依赖

这是 npm 最基本的依赖,通过命令 npm i xxx -S 或者 npm i xxx --save 来安装一个包,并且添加到 package.json 的 dependencies 里面(这里 iinstall 的简写,两者均可)。

如果直接只写一个包的名字,则安装当前 npm registry 中这个包的最新版本;如果要指定版本的,可以把版本号写在包名后面,例如 npm i webpack@3.0.0 --save

npm install 也支持 tag,tar 包地址等等,不过那些不太常用,可以查看官方文档

dependencies 比较简单,我就不再多做解释了。注意一点:npm 5.x 开始可以省略 --save,即如果执行 npm install xxx,npm 一样会把包的依赖添加到 package.json 中去。要关闭这个功能,可以使用 npm config set save false

npm install

把逻辑代码pull到本地之后,通过npm install拉取到node_modules文件夹。依赖管理。一定要初始化,要有package.json文件

Express

介绍

  • Express 是一个第三方模块,用于快速搭建服务器

  • Express 是一个基于 Node.js 平台,快速、开放、极简的 web 开发框架

  • express保留了http模块的基本API,使用express的时候,也能使用http的API

  • express还额外封装了一些新方法,能让我们更方便的搭建服务器

  • Express 官网

  • Express 中文文档(非官方)

  • Express GitHub仓库

安装express

项目文件夹中,执行npm i express即可下载安装express。

注意:express不能安装在express文件夹中。否则安装失败。

使用express搭建web服务器

步骤:

  1. 加载express模块

  2. 创建express服务器

  3. 开启服务器,设置端口

  4. 监听浏览器的请求并进行处理

代码演示:

// 1、加载express模块
const express = require('espress')

// 2、创建express服务器
const app = express()

// 3、设置端口、开启服务器
app.listen(8001, () => console.log('开启服务器'))

// 4、监听浏览请请求并处理
app.get('GET请求的地址', 处理函数)
app.post('POST请求的地址', 处理函数);</pre>

express封装的新方法

express之所以能够实现web服务器的搭建,是因为其内部对核心模块http进行了封装。提供一些非常好用的新方法。http方法也能使用。

  • req

    • 获取POST请求体 req.body

    • 获取GET请求参数(查询字符串格式) req.query

    • 获取GET请求动态参数(动态路由) req.params

    • 其他...

  • res

    • res.sendFile(文件的绝对路径) -- 读取文件,并将结果响应。后面不要有res.send()

    • res.set({name, value}) -- 设置响应头

    • res.status(200) -- 设置响应状态码

    • res.send(字符串或对象) -- 响应结果。end()和字符集效果

    • res.json(对象) -- 以JSON格式响应结果

    • res.jsonp() -- 以JSONP格式响应结果

    • 其他...

  • app

    • app.get() -- 处理客户 端的GET请求

    • app.post() -- 处理客户端的POST请求

    • app.use() -- 设置应用级别的配置

    • 其他...

  • express

    • express.static() -- 开放静态资源

    • express.urlencoded() -- 获取POST请求体

    • 其他...

GET接口

app.get('请求的URL', callback);

查询字符串 常规参数

?id=10&name=lw

// 写接口
app.get('/index', (req, res) => {
console.log(req.query); // { id: '3', bookname: 'zxx', age: '20' }
});</pre>

动态参数(动态路由)

url/:id/:name

// /index/:id/:name 接口 动态参数
// 浏览器的请求:http://locallhost:3001/index1/20/ww

app.get('/index1/:id/:name', (req, res) => {
  console.log(req.params) //{ id: '20', name: 'ww' } 可以获取所有动态参数
  res.send()
})</pre>
  • 匹配到所有的GET请求-配置404

    • app.get('*', (req, res) => {}) 他能够匹配到所有的GET请求,所以把它放到所有接口的最后。

POST接口

app.post('请求的URL', callback)

获取POST请求体

  • GET没有请求体。POST方式才是才有请求体

  • 请求体,即客户端提交的数据

  • 可以使用http模块中的方法,获取请求体

  • POST请求体,有哪些格式

    • 查询字符串 -- 对应的Content-Type: application/x-www-form-urlencoded

    • FormData对象 -- 对应的Content-Type: multipart/form-data; --XXADFsdfssf

请求体是查询字符串

const path = require('path')
const express = require('express')
const app = express()

app.listen(8001, () => console.log('开启服务器'))

// 全局应用级配置
//可以帮我们接收 content-type: application/x-www-form-urlencoded类型的请求体
app.use(express.urlencoded({ extended: false }))

app.post('/index', (req, res) => {
// 获取post的请求体 请求体是查询字符串
// 配置之后,任何一个POST接口,都可以通过req.body获取到请求体的内容
console.log(req.body) //[Object: null prototype] { name: 'zs', age: '20', id: '10' }
res.send()
})</pre>

postman发送一个POST方式的请求,来配合测试:

点击POST,选中body,选中x-www-formurlencoded。模拟发送post请求

请求体是FormData对象

需要使用第三方模块(multer)才能够获取到。

案例:图书接口

使用cors模块,实现跨资源共享 允许跨域 1、npm i cors 2、加载 const cors = require('cors) 3、app.use(cors())

使用cors模块,实现跨资源共享 允许跨域
1、npm i cors
2、加载 const cors = require('cors)
3、app.use(cors())
const cors = require('cors')
const fs = require('fs')
const path = require('path')
const express = require('express')
const app = express()
app.listen(3006, () => console.log('开启服务器'))

// 接收post请求的 查询字符串参数 req.body
app.use(express.urlencoded({ extended: false }))

// 通过应用级的配置,设置接口可以跨域
// app.use((req, res, next) => {
//   res.set({
//     'Access-Control-Allow-Origin': '*',
//   })
//   next()
// })
//  cors 的第三方模块 实现跨域
app.use(cors())

// 获取图书列表路由配置
app.get('/api/getbooks', (req, res) => {
  // 获取图书列表文件
  let data = require(path.join(__dirname, './books.json'))

  res.json({
    status: 200,
    msg: '列表接口读取成功',
    data: data,
  })
})

// 添加图书
app.post('/api/addbook', (req, res) => {
  // 获取参数
  req.body.id = Date.now() //使用时间戳做id
  // 获取图书列表文件
  let data = require(path.join(__dirname, './books.json'))
  // 把获取到的参数添加到图书列表文件中
  data.push(req.body)
  // 写入数据
  fs.writeFile(
    path.join(__dirname, './books.json'),
    JSON.stringify(data, null, 2),
    (err) => {
      if (err) {
        res.json({
          status: 500,
          msg: '添加图书失败',
        })
      } else {
        res.json({
          status: 201,
          msg: '添加图书成功',
        })
      }
    }
  )
})

// 删除图书
app.get('/api/delbook', (req, res) => {
  // 2、读取数据文件内容
  // 3、删除id对应数据项
  // 4、向数据文件写入新数据

  // 1、拿到id
  let id = req.query.id //拿到get请求 静态数据id

  // 2、验证id 找不到或者不规范的时候
  if (!id) {
    res.json({
      status: 500,
      msg: '未指定要删除的图书Id',
    })
    return
  }
  // 拿到文件数据
  let data = require(path.join(__dirname, './books.json'))

  // 筛选数据,将选中的id删除
  data = data.filter((item) => item.id != id)

  // 写入数据
  fs.writeFile(
    path.join(__dirname, './books.json'),
    JSON.stringify(data, null, 2),
    (err) => {
      if (err) {
        res.json({
          status: 500,
          msg: '删除图书失败!',
        })
      } else {
        res.json({
          status: 200,
          msg: '删除图书成功!',
        })
      }
    }
  )
})

</pre>

使用第三方模块,实现跨域资源共享

实现跨域资源共享,可以使用一个叫做 cors 的第三方模块。推荐使用它来实现跨域资源共享。

使用方法:

  • 下载安装cors npm i cors

  • const cors = require('cors'); --- 加载模块

  • app.use(cors()); -- 使用use方法即可

开放静态资源

  • 什么是静态资源:CSS文件、图片文件、JS文件等等

  • 开放静态资源:开放出来,使客户端能够访问

  • 具体做法:

    • 比如,允许客户端访问某文件夹中的文件

    • app.use(express.static('绝对路径'))d通过应用级配置

【注】如果配置多个静态资源目录有同名,会按照顺序显示。

配置一个别名,可以用来标识目录app.use('/别名',express.static('绝对路径'))

通过别名访问,互不干扰

接收POST请求体

  • POST请求体的类型(Content-Type)

    • application/x-www-form-urlencoded 比如:id=1&name=zs&age=20

    • form-data 比如,提交的是FormData对象

    • application/json 比如,提交的是 {"id": 1, "name": "zs", "age": 20}

    • 其他...

  • 服务器端接收不同类型的请求体,使用的方式是不同的

    • urlencoded ---> app.use(express.urlencoded({extended: false}));

    • application/json ---> app.use(express.json()); -- 没有演示

    • form-data ---> 服务器端使用第三方模块处理(multer

当初学习ajax的时候,如果是POST请求,为什么要加Content-Type

路由

express中的路由

指的是客户端的请求与服务器处理函数之间的映射关系

Express 中的路由分 3 部分组成,分别是请求的类型、请求的 URL 地址、处理函数,格式如下

// 路径 ,就是我们之前说的接口的处理程序
app.get('/api/getbooks', (req, res) => {
});

app.post('/api/getbooks', (req, res) => {
});

app.post('/api/addbook', (req, res) => {
});</pre>

每当一个请求到达以后,都需要先经过路由的配置,只有匹配成功之后,才会调用对应的处理函数。

在匹配的时候,会按照路由的顺序进行匹配,如果请求的URL和请求的方式同时匹配成功,则Express会将这次的请求,转交给对应function函数进行处理。

模块化路由

为了方便对路由进行模块化管理。Express不建议直接将路由挂载到app上面运行,而是推荐将路由抽离出来成为单独的模块。抽离的步骤如下:

  1. 创建路由对应的.js文件:

    创建router.js 存放 登录、注册、验证码三个路由

  2. 引入express模块,

const express = require('express');

  1. 调用express.Router()函数创建路由对象。路由对象router中会自动携带req、res。不用额外传递

const router = express.Router();

  1. 向路由对象上挂载具体的路由--配置路由。路由对象叫啥,下面就叫啥。不要写app了。

// 把app换成router,比如
router.get('/xxx/xxx', (req, res) => {});
router.post('/xxx/xxx', (req, res) => {});</pre>

  1. 导出路由对象,使用nodule.express向外共享路由文件

    module.exports = router;

  2. 在主文件中引入路由文件

    const router = require('./router.js')

  3. 在主文件中使用路由app.use(router)

// app.js 中,将路由导入,注册路由
const login = require('./router/logon.js');
app.use(login)

// app.use(require('./router/heroes.js'));
app.use( require(path.join(__dirname, 'router', 'heores.js')) );</pre>

为路由模块添加前缀

路由模块化之后,可以按照须有拆分成多个路由文件。每个被拆分的文件都要有引入创建导出

我们可以省略路由模块中的 /api 前缀,而是在注册路由的时候,统一设置。路由文件中,把前缀 /api 和 /my 去掉

// 导入路由模块,并注册路由
app.use('/api', require(path.join(__dirname, 'router', 'login.js')) );
app.use('/my', require(path.join(__dirname, 'router', 'heroes.js')) );</pre>

使用路由模块的好处

  • 分模块管理路径,提高了代码的可读性

  • 可维护性更强

  • 减少路由的匹配次数

  • 权限管理更方便

  • etc...

其他:

throw err是js中的语法。抛出语句异常

作用:

1、把错误的信息打到控制台

2、阻止程序的运行

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容

  • Node介绍 为什么要学习Node.js 企业需求具有服务端开发经验更改front-endback-end全栈开发...
    废弃的种子阅读 435评论 0 0
  • node.js 介绍 node.js是什么 node.js 是一个开发平台,就像java开发平台...何为开发平台...
    小浅_阅读 1,157评论 0 6
  • 一. 简介 1.Node.js是js运行在服务器的一个平台2.Node中,每一个js文件中的代码都是独立运行在一个...
    codingZero阅读 411评论 0 0
  • 4. 增加邮箱验证功能 刚刚我们只是实现了登录的流程,不过里面用的验证码是假的,我们考虑下实现真正的邮箱验证码发送...
    小五同学H阅读 356评论 0 0
  • 个人入门学习用笔记、不过多作为参考依据。如有错误欢迎斧正 目录 简书好像不支持锚点、复制搜索(反正也是写给我自己看...
    kirito_song阅读 2,458评论 1 37