nodejs+express实现接口开发

735 阅读14分钟

什么是nodejs

node其实不是语言,是一个能够运行js的环境的平台,做前端的知道js,那么node中运行的js又跟前端运行的js又有什么差异呢。

前端的js: 脚本,不能单独运行的,需要嵌入在html里面。包括ECMAScript(js语法标准),Dom,Bom。

后端的js: node的作者把chrome的v8引擎抽取出来,做成了node平台,所以js可以独立的运行。但是后端的js只有ECMAScript(js语法标准),没有DOM和BOM。

可以查看官网学习:nodejs.cn/learn

javascript=ECMAScript + DOM + BOM

nodejs=ECMAScript + I/O(ps:i就是input输入,O就是output输出,一起就是基本输入输出设备)

为什么要学习nodejs

笔者因为不太懂接口的一些方式,比如post方式body里面的一些Content-Type参数,所以需要把它弄明白,顺便把nodejs学习一下,也为了方便自己写一些接口来测试前端的一些功能,再则现在更多的也是要求全栈了。

前端转全栈为什么选nodejs呢,经过上面的介绍,大家应该也明白了nodejs是一个环境,但是它的语言还是js,遵循ECMAScript语法标准(就是前端的js语法,只是后端少了BOM,DOM操作),那么学起来我们的成本更低,并且不会忘记js,如果选java那么学了那边这边忘了,或者那边久了没写又忘了不是得不偿失了,所以笔者很果断的选择了nodejs。

Content-Type 的认识

要学会nodejs一定需要知道Content-Type,那么我们先来了解一下什么是Content-Type,它有什么用,请接着往下读。

Content-Type 有什么用

接口发送参数、接收响应数据,都需要双方约定好使用什么格式的数据,例如 json、xml。
只有双方按照约定好的格式去解析数据才能正确的收发数据。
Content-Type 就是用来告诉你数据的格式,这样我们才能知道怎么解析参数。
如下图,我们可以看到接口的请求头和响应头中都有 Content-Type.

image.png

常见的 Content-Type

application/json:JSON数据格式,现在非常流行的格式
application/x-www-form-urlencoded:很常见的一种数据格式,post请求中通常默认是这个
multipart/form-data:上传文件时我们需要用到这个格式
application/xml:XML数据格式
text/html:HTML格式
text/plain:纯文本格式
image/png:png图片格式\

xml格式认识

1.2 XML的特点
有且只有一个根节点;
数据传输的载体;
所有的标签都需要自定义;
是纯文本文件
格式统一,符合标准;
容易与其他系统进行远程交互,数据共享比较方便。 

1.3 XML的缺点
A、XML文件庞大,文件格式复杂,传输占带宽;
B、服务器端和客户端都需要花费大量代码来解析XML,导致服务器端和客户端代码变得异常复杂且不易维护;
C、客户端不同浏览器之间解析XML的方式不一致,需要重复编写很多代码;
D、服务器端和客户端解析XML花费较多的资源和时间。

<?xml version="1.0" encoding="utf-8"?>
<country>
   <name>中国</name>
   <province>
       <name>黑龙江</name>
       <citys>
           <city>哈尔滨</city>
           <city>大庆</city>
       </citys>    `
   </province>
</country>

x-www-form-urlencoded 格式案例

这个格式会用=号连接参数名和参数值,并且会经过urlencode编码。
例如:title=test&sub%5B%5D=1&sub%5B%5D=2&sub%5B%5D=3
我们来看下 Chrome 中的请求参数(查看时需要点击view source才能看到原始数据,否则是经过解析后的),如下图,我们传递了 username 和 password 两个参数,可以看到他们是用=拼接参数和值,用&号拼接多个参数

image.png

multipart/form-data 格式案例

这个格式会在多个参数之前插入一段分隔字符,如下图,我们传递了 page 和 pageSize 两个参数,他的分隔字符串在 Content-Type 中用 boundary 标明了,这样服务端解析的时候才知道怎么拆分参数。

image.png

postman工具的使用

postman是我们学习nodejs需要的工具,用来调试接口,我们学习nodejs需要学会开服务器,学会中间件的使用,学会做一些简单的接口。

postman工具的界面

image.png

POST方法body类型的介绍

以post类型接口为例,先来介绍一下post类型接口的body有哪些Content-Type

post参数格式Content-Type参考示例
表单提交application/x-www-form-urlencodedusername=abc123&password=123
JSON提交application{"username": "abc123","password": "123"}
xml提交text/xml<?xml version="1.0" encoding="utf-8">悟空传

1.form-data(常用于上传文件)

Content-Type:multipart/form-data,它将表单的数据组织成Key-Value形式,用分隔符boundary(boundary可任意设置)处理成一条消息。由于有boundary隔离,所以既可以上传文件,也可以上传参数。
既可以上传文件等二进制数据,也可以上传表单键值对,只是最后会转化为一条信息。当设置multipart/form-data,http会忽略 contentType 属性

2.x-www-form-urlencoded(post请求常用)

Content-Type:application/x-www-from-urlencoded,将表单内的数据转换为Key-Value。
application/x-www-form-urlencoded是默认的MIME内容编码类型,它在传输比较大的二进制或者文本数据时效率极低。
只能上传键值对,不能用于文件上传。不同的field是用&区分开的。

3.raw(json数据)

Content-Type:application/json,可以上传任意格式的文本,可以上传text、json、xml、html等。

4.binary(只可以上传二进制文件)

Content-Type:application/octet-stream,只可以上传二进制数据,通常用来上传文件。由于没有键值,所以一次只能上传一个文件。

正式开始学习nodejs

安装nodejs

我们需要先安装一下nodejs,相信能看到这里的童鞋已经有一定的前端基础了,也安装了nodejs,如果没有的同学先去安装nodejs喔。 可以使用node -v来检测一下是否有安装nodejs,如果有会出现一个版本号,如下图。

没有的童鞋可以去官网下载一个来安装,一直下一步下一步就好没有什么技术含量。

官网下载地址:nodejs.cn/download/

image.png

image.png

nodejs可以直接执行js文件,假设我们有一个js文件(helloworld.js),在cmd中进入到helloword.js所在的文件夹,执行指令node helloworld.js

//helloworld.js
console.log("hello world")

cmd中就会输出hello world效果如下

image.png

js分模块化语法

方法一:module.exports 一个文件中只能出现一次,出现多次的话后者会覆盖前者

module.exports = show; //导出模块,暴露模块
let fn = require("./02 exports");  //相对路径的写法
module.exports = {//导出多个数据的时候:
  show, 
  obj,
  num,
};
let { num } = require("./02 exports");

方法二:export

exports.show = show;
exports.obj = obj;
exports.count = num;
let { count } = require("./04 exports");

模块化规范有哪些

  • AMD(异步,推崇依赖前置)      代表:requirejs(异步)  优点:模块化开发    define()定义模块,require()引入模块
  • CMD(异步,依赖后置)      代表:seajs(中国人写的-王保平(玉伯),目前就职于阿里),现在seajs不再维护(异步)  优点:模块化开发    define()定义模块,require()引入模块
  • ES6  module  (同步)   导入:import  导出:export
  • commonjs    代表:nodejs遵循的规范(同步)  实际上,nodejs提供很多的方法都是异步操作(回调函数) :导出:module.exports 、exports  导入:require()
  • script标签  引入js文件,一个js就是一个模块,依赖要放在前面(同步),缺点:前面的js会影响后面js的加载:导入:引入script写好src
    • 同步:阻塞模式(会影响后面的代码)
    • 异步:非阻塞模式

node中的模块类型

原生模块:安装nodejs就自带的,直接引入使用。
文件模块:json数据。
第三方模块:安装再引入使用,如express,mysql,mongo。
自定义模块:exports,module.exports,require()。

express

安装express

npm init -y
npm install express -S 

什么是express

它是一个开服务器的js文件,就是我们说的模块

Express 是一个第三方模块,对原生模块封装了一套更灵活、更简洁的应用框架,其在 Node.js 环境的地位和作用好比 jQuery 在前端的地位和作用。使用 Express 可以快速地搭建一个完整功能的网站;为了方便重启服务器,不用每次改完就要运行node命令,建议大家安装superviosor server.js 一旦你有更新,就会自动刷新服务器 官方中文API:www.expressjs.com.cn/

使用express

写一个简单的server.js文件,在同级下准备好index.html文件,node中去执行这个文件,浏览器访问http://localhost:8080 便能看到写的index.html文件

//1.安装 express  : npm i express -S 保存生产依赖

//2.引入模块
let express = require("express"); //绝对路径

//3.使用模块
let app = express(); //实例化过程

// app.use(express.static("./",{index:'main.html',maxAge:5000})); //利用express的static方法开启静态资源服务器
app.use(express.static("./")); //利用express的static方法开启静态资源服务器

//4.开启服务器

app.listen(8080, () => {
  console.log("服务器已开启,请访问:http://localhost:8080");
});

创建一个最小的demo

const express = require('express')
const app = express()
const port = 3000

app.get('/', (req, res) => {
  res.send('Hello World!')
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})

访问http://localhost:3000

全局安装supervisor

yarn add supervisor -g

什么是supervisor

用supervisor管理的进程,当一个进程意外被杀死,supervisor监听到进程死后,会自动将它重启,很方便的做到进程自动恢复的功能,不再需要自己写shell脚本来控制。

官方中文API:www.expressjs.com.cn/

参考文献: www.cnblogs.com/hls-code/p/…

使用supervisor

supervisor server.js

开服务器的一些语法

app.METHOD(PATH, HANDLER)

  • app是 的一个实例express。
  • METHOD是一个HTTP 请求方法,小写
  • PATH是服务器上的路径。
  • HANDLER是路由匹配时执行的函数。
app.get('/', function (req, res) {
  res.send('Hello World!')
})
app.use(express.static('./'))
app.use(express.static({path:"./",index:'main.html',maxAge: 500})
//访问index.html

app.use(express.static('files'))
//如果要使用多个静态资源目录,请多次调用 `express.static` 中间件函数

app.use(express.static('public'))
//通过如下代码就可以将 `public` 目录下的图片、CSS 文件、JavaScript 文件对外开放访问了
//http://localhost:3000/images/daji.jpg

express.static(root, [options])
app.use('/static', express.static('public'))
//虚拟路径
http://localhost:3000/static/images/daji.jpg



const path = require('path')
app.use('/static', express.static(path.join(__dirname, 'public')))

express中间件

中间件其实就是一个函数,但是函数不一定是中间件,中间件例如

app.use("/login", (request, response, next) => {
    console.log('注意这里打印的东西是在命令行中显示的,通常被用来调试接口')
})
//其中后面的这个函数就是一个中间件

实现一个接口(实现一个路由),在postman中调用,通常是多个路由并用

//use() 代表什么请求方式都可以进入
app.use("/login", (request, response, next) => {
  /*
    request:请求对象,前端发送的请求相关数据都存在这个对象里面
    response:响应对象,用这个对象里面的send()就可以给前端响应数据
    next:进入下一个中间件
  */
  console.log("进到这个login路由里面了"); //打印到cmd的命令行里面,一般是用于后端自己测试接口
  response.send("登录成功"); //一个路由下只能有一个响应
});

端口范围,以及next()何时使用

一般端口范围尽量写1000~60000 除了最后一个路由,其余路由都需要使用

实现两个路由,并且分别调用

app.use("/login", (request, response, next) => {
  /*
    request:请求对象,前端发送的请求相关数据都存在这个对象里面
    response:响应对象,用这个对象里面的send()就可以给前端响应数据
    next:进入下一个中间件
  */
  console.log("进到这个login路由里面了"); //打印到cmd的命令行里面,一般是用于后端自己测试接口
  response.send("登录成功"); //一个路由下只能有一个响应
});

app.use("/reg", (request, response, next) => {
  /*
    request:请求对象,前端发送的请求相关数据都存在这个对象里面
    response:响应对象,用这个对象里面的send()就可以给前端响应数据
    next:进入下一个中间件
  */
  console.log("进到这个reg路由里面了");
  response.send("注册成功");
});

image.png

RESTful接口规范

  • 根据请求类型实现不同的接口
  • 根据url地址实现不同接口
  • 接口可读性强

例如:

  • 获取商品数据---get
  • 增加一个商品---post
  • 删除一个商品---delete
  • 修改一个商品---patch/put
    • patch---部分修改
    • put---全部修改

需要给前端返回使用方法例如:

exapmle

用户管理:
    * 验证用户名是否存在 :get
    * 注册 : post
    * 登录 : get
    * 退出 : delete
    * 删除用户 : delete
    * 查询用户列表 :get
    * 修改用户信息 :put

上面例子判断的依据可以根据是否要插入一条数据到数据库,需要插入则用post

制定接口时数据的接收

  • get请求的数据---req.query.**
  • post请求的数据---req.body---undefined---需要中间件转一下才能看的到

发送请求

post请求的处理

app.use(express.urlencoded()); 
//处理name=马源123&age=18
//body实际上传递过来的数据是这样的,不能直接访问到,需要转成对象才能直接访问到
app.use(express.json());
//处理json数据  '{name:王祖贤,age:18}'
//后端拿到的是字符串对象,将其转化为对象

接口的动态路由传参跟body传参的区别

//body传参
app.post("/user/reg", (req,res)=>{
    res.sent('成功')
})
//动态路由传参
//http://localhost:8090/user/edit/2
app.put("/user/reg/:id", (req,res)=>{
    console.log(req.params.is) 
    res.sent('成功')
})

路由的分模块化

结构如下图

image.png

api>server.js 开启服务器

//express的使用-开启服务器

//1.安装 express  : npm i express -S 保存生产依赖

//2.引入模块
let express = require("express"); //绝对路径
let { PORT } = require("./config.json");
let allRouter = require("./router/index"); //allRouter是中间件
// console.log(config);

//3.使用模块
let app = express(); //实例化过程

// app.use(express.static({path:"./",index:'main.html',maxAge:5000})); //利用express的static方法开启静态资源服务器
app.use(express.static("./")); //利用express的static方法开启静态资源服务器

//使用路由进行接口管理:主路由
app.use(allRouter);

//4.开启服务器

app.listen(PORT, () => {
  console.log("服务器已开启,请访问:http://localhost:" + PORT);
});

api>config.json-配置端口

{
  "PORT": 2004
}

api>router>index.js

//主路由
let express = require("express"); //绝对路径

//创建路由对象
let Router = express.Router(); //Router==app
//引入子路由
let userRouter = require("./modules/users"); //用户管理子路由
let goodRouter = require("./modules/goods"); //用户管理子路由
let orderRouter = require("./modules/orders"); //用户管理子路由

Router.use("/user", userRouter); //用户管理子路由
Router.use("/good", goodRouter); //商品管理子路由
Router.use("/order", orderRouter); //订单管理子路由

// Router.use("/good", (req, res) => {
//   console.log("进入主路由");
//   res.send("进入good路由");
// });

// Router.use("/order", (req, res) => {
//   console.log("进入主路由");
//   res.send("进入order路由");
// });

module.exports = Router; //导出主路由

api>router>modules>goods.js

//子路由
let express = require("express"); //绝对路径

//创建路由对象
let Router = express.Router(); //Router==app

module.exports = Router;

api>router>modules>order.js

//子路由
let express = require("express"); //绝对路径

//创建路由对象
let Router = express.Router(); //Router==app

module.exports = Router;

api>router>modules>users.js

//子路由
let express = require("express"); //绝对路径

//创建路由对象
let Router = express.Router(); //Router==app

/*
  用户管理:restful接口规范
    * 验证用户名是否存在 :get
    * 注册 : post
    * 登录 : get
    * 退出 : delete
    * 删除用户 : delete
    * 查询用户列表 :get
    * 修改用户信息 :put
*/

let userinf = [
  {
    uid: 1,
    name: "leyi",
  },
  {
    uid: 2,
    name: "jack",
  },
  {
    uid: 3,
    name: "志远",
  },
];

//验证用户名是否存在
Router.get("/checkname", (req, res) => {
  // console.log(req, 888);
  // console.log(req.query, 999);
  let { name } = req.query;
  // console.log(name);
  let result = userinf.filter((item) => item.name == name).length; //找到名字相同,返回数组
  let data = {};
  if (result) {
    //非0数字都是真。 细节: 0 假; '0' 真; '' 假
    //找到:不给注册
    data = {
      code: 0,
      message: "该用户已存在,不能注册",
    };
  } else {
    //没有找到:允许注册
    data = {
      code: 1,
      message: "允许注册",
    };
  }
  // res.send("666");
  res.send(data);
});

module.exports = Router;

关系型数据库跟非关系型数据库基础差异

image.png

image.png

mongoDB下载中心

www.mongodb.com/try/downloa… 下载界面如下:

image.png 检测是否有安装好,随便打开一个目录

image.png

安装Robo3t

安装一个软件才能看到mongoDB数据库里面数据的变化

创建链接

image.png

创建数据库

image.png

查找数据

image.png

写mongoDB接口

安装mongoDB模块

npm install mongoDB --save

mongo链接数据库语法

//写代码对mongoDB的数据进行增删改查  CRUD
//1.安装数据库管理模块  npm i mongodb -S
//2.引入mongodb模块
const { MongoClient } = require("mongodb");

//连接mongoDB
MongoClient.connect("mongodb://localhost:27017", async (err, client) => {
  if (err) throw err;
  // 1.连接数据库,无则自动创建
  let db = client.db("h52004");
  //2.连接集合
  let col = db.collection("users");

  //3.CRUD 增删改查
  //增 C create

  //删 D delete

  //改 U update
  
  //查 R retrieve
  let arr = await col.find({ username: "Jason Williams" }).toArray();
  console.log(arr);

  //   db.createCollection("users", function (err, res) {
  //     if (err) throw err;
  //     console.log("创建集合!");

  //     //增

  //     //删
  //     //改
  //     //查
  //     client.close();
  //   });
});

数据库的备份和还原

链接数据库的几个必不可少的条件

1.必须有数据库 2.有开启node serve.js服务,开启端口可访问 3.链接url,数据库名,集合名