10分钟速成Express

246 阅读11分钟

前言

很久之前囫囵吞枣的学过一点node,就、最近决定用node+vue写个博客项目,所以重新学习了express的相关内容。

初始搭建

创建项目

  1. npm init给项目命名创建项目
  2. 终端进入项目,安装express依赖,npm i express
  3. js文件中引入express使用
const express = require('express');

const app = express();

app.get('/', (req, res) => {
    res.send('有人请求了根路径')
})

app.listen(3000, function () {
    console.log("服务器正在运行 http://localhost:3000")
});

之后终端使用node index.js(tab键补全)运行上面代码

0.png

路由和中间件

express完全是由路由和中间件构成的框架,本质上来说express应用就是为了监听不同的路径调用各种中间件,中间件本身是一个函数,也可以叫插件,只是在express里面更习惯叫做中间件

路由

路由:前端访问不同的地址,后端返回不同的数据,这就是后端路由
如果/users/login接口是登录用的,/users/reg接口是注册用的。 监听不同的路径执行不同的函数,从而处理不同的请求

这个路由一般是在app上使用的,一般称为应用级别的路由

中间件

中间件就是一个函数,带有三个参数,req,res,next req 请求的相关信息 res 响应的相关信息 next函数 如果调用了next,就会去执行下一个匹配到路由的中间件

app.use(
    function (req, res, next) {
        console.log("中间件1")
        res.send("中间件1")
        next()
    },
    function (req, res, next) {
        console.log("中间件2")
        next()
    },
    function (req, res, next) {
        console.log("中间件3")
    });

终端全部显示

3.png

注意下面这样两个中间件都不会正常运行

app.get("/user/login", function (req, res, next) {
    console.log("登录中间件")
    next()
})
app.get("/user/login", function (req, res, next) {
    console.log("最后一个中间件")
    res.send("nice ")
})

正确的写法应该是

app.use(
    function (req, res, next) {
        console.log("中间件1")
        res.send("中间件1")
        next()
    },
    function (req, res, next) {
        console.log("中间件2")
        next()
    },
    function (req, res, next) {
        console.log("中间件3")
        next()
    });
app.use(
    function (req, res, next) {
        console.log("中间件4")
        next()
    });
app.get(
    "/user/login",
    function (req, res, next) {
        console.log("登录中间件")
        next()
    }, function (req, res, next) {
        console.log("最后一个中间件")
    }
)

若没有第二个app.use里面的next,那么就不执行后面get请求了 中间件也可以是写在外面的js文件里面,然后导入使用 比如新建login.js

function fn(req, res, next) {
    console.log("登录中间件")
    next()
}
module.exports = fn;

之后在index.js中引入使用

let login = require("./login.js");
app.get(
    "/user/login",
    login,
    function (req, res, next) {
        console.log("最后一个中间件")
    }
)

附上一个终端运行截图

4.png

通过路由挂载中间件

app.use(中间件监听的路径,中间件函数) 参数两个:路径,*是匹配任何路径;回调函数,找到路径之后会执行回调函数。回调函数一般都是第三方封装好的函数,这个函数叫做中间件。

// 通过路由挂载中间件
app.use("/user/login", function (req, res) {
    console.log("打开/user/login")
    res.send("用户登录成功")
})

因为之前运行脚本开启了3000端口,需要关闭重启才能在规定目录看到想看的。

1.png

我们需要注意的是:修改了 server.js 文件,需要停止服务(ctrl + c),再次启动才会生效;
有了 nodemon,就不用频繁手动重启 server.js ,因为 nodemon 可以监视源码改动,并自动重启服务。这样我们只需要专注写代码逻辑,不需要过多关注服务。

全局安装nodemon

npm install -g nodemon

package.json 中的 nodemonConfig 选项中配置nodemon

"nodemonConfig": {
  "watch":["src/"],
  "ext":"js json"
}

之后修改代码不需要重启服务只需刷新页面即可
使用匹配所有路径,下面的就不匹配了

app.use("*", function (req, res) {
    console.log("匹配所有路径")
    res.send("匹配所有路径 ")
})

// 通过路由挂载中间件
app.use("/user/login", function (req, res) {
    console.log("打开/user/login")
    res.send("用户登录成功hahah ")
})

2.png

http请求 http有很多请求方式,常见的: get请求、post上传、put修改、patch修改、delete删除 使用app.get 可以监听get请求,其他类似 postman可以发起不同的请求,可以作为请求测试工具。

postman使用描述 服务器启动的时候,使用postman进行测试 新建collection集合 Blog接口测试 接着在集合里面添加请求add request

路由中间件

专门处理路由的中间件就是路由中间件,路由中间件是express内置的一个中间件。后端编写接口,前端调用接口。
后端接口功能包括用户相关操作(登录,注册),文章相关操作(发布文章,删除文章,修改文章,文章列表,文章详情等等)
借助路由中间件将用户和文章相关操作分散在不同的js文件中
这种路由主要对应用级别的路由做了细分处理,就是路由级别的路由

操作步骤

  1. 获取路由中间件,新建routes/users.js
  2. 处理get请求,router.get(监听请求的路径,处理回调函数)
  3. 处理post请求,router.post(监听请求的路径,处理回调函数)
  4. 导出router对象 代码展示 users.js是用户相关操作
const express = require("express");
//创建一个路由中间件
const router = express.Router();
// /user/reg
//配置路由
router.get("/reg", function (req, res) {
    console.log("reg请求");
    // 向服务器发送json数据
    res.send({ username: "zhangsan" });
})

// 导出路由中间件
module.exports = router;

之后导入app.js(一开始我把index.js作为入口文件,后来将index移动到demo文件夹,新建了app.js作为新的入口文件)

let userRouter = require("./routes/users");
app.use("/users", userRouter)

之后启动服务器运行截图

5.png

路由中间件请求参数获取

get请求参数的获取

req.query
下面代码是users.js中的,因为users.js是app.js中的路由所以下面是监听/ users / login路径的get请求,如果在前端请求的url里面输入 http://localhost:3000/users/login?username=Angle&password=123456,在终端可以看到打印的请求的query参数

// 监听get请求 / users / login
//url中的搜索参数
router.get("/login", function (req, res) {
    // 获取get请求的query参数
    console.log(req.query);
    // 返回json数据
    res.json({ name:小米糕});
});

6.png

7.png

get请求的另外一种传参

获取get请求的url中的参数

router.get("/info/:id", function (req, res) {
    console.log(req.params);
    res.json(req.params);
})

8.png

9.png

post请求参数的获取

//user.js
router.post('/profile', (req, res, next) => {
    console.log(req.body)
    res.json(req.body)
})

//app.js
app.use(express.json()) 
app.use(express.urlencoded({ extended: true })) 

上面users.js中req.body包含在请求正文中提交的数据键值对。默认情况下,它是 undefined
app.js中解析前端请求的请求体的数据 ,解析json和x-www-form数据
post请求需要借助工具apipost或者postman来发送 我是用postman 两个小时遇到的问题是发送post请求服务器返回undefined。

11post请求返回undefined.png

12正确的post请求.png

静态资源托管中间件

html,css,js图片等都是静态资源,静态资源一般不需要处理直接返回给浏览器。
网页中发起请求,请求接口返回的数据叫做动态资源,比如JSON数据。 动态资源一般后端会处理,比如解析前端的请求过来的url和参数,根据url和参数返回不同的json数据。
使用express创建一个静态资源服务器,express.static() 当前目录下的文件夹public为静态资源文件夹,有请求发过来会先到静态资源文件夹下找有没有静态文件,有的话就直接返回静态文件,比如访问http://localhost:3000/a.js,就会去pubilc文件夹找a.js文件,在app.js里server.use(express.static('public'));

app.use(express.static("public"));

可以在浏览器地址栏输入http://localhost:3000/cool.jpg查看静态资源图片 这里一开始实践的时候我在地址栏输入之后回车get不到,后来检查发现我的public在demo子文件夹里面,于是删除,重新在Blog文件夹下面新建public文件夹。之后可以正常看。

假如在public文件夹下面还有多个文件夹,比如图片放在img文件夹。 那么访问的时候需要在url里面加上public的子文件夹路径。 http://localhost:3000/img/cool.jpg

express脚手架创建项目

express内置了许多中间件,逐个配置较复杂,一个后端项目需要一些别的中间件比如日志插件,错误处理插件等等,借助通用的项目模板可以简化配置过程。
通过应用生成器工具express-generator可以快速创建一个应用的骨架。 安装express-generator

npm install express-generator -g

创建项目

express -e Dreamlab

-e是指定了项目中的模板引擎。

前后端不分离

MVC是一种经典的设计模式,全名Model-View-Controller即模型-视图-控制器。这种模式用于应用程序的分层开发。大致就是模型和视图需要通过控制器来进行粘合。例如,用户发送一个HTTP请求,此时该请求首先会进入控制器,然后控制器去获取数据并将其封装为模型,最后将模型传递到视图中展现。,需要说明的是这个View可以采用Velocity,Freemaker等模板引擎,可使开发过程中人员分工更明确提高开发效率。

14.png

前后端分离

前后端分离(解耦)的核心思想:前端html页面通过ajax调用后端的Restful API并使用Json数据进行交互。
前端负责开发页面,通过接口(ajax)获取数据,采用Dom操作对页面进行数据绑定,最终是由前端把页面渲染出来。
在互联网架构中一般有两种服务器:web服务器:一般指像nginx,apache这类的服务器,他们一般只能解析静态资源,
应用服务器:一般指像tomcat,jetty,resin这类服务器可以解析静态资源和动态资源,但是解析静态资源的能力没有web服务器好。 一般只有web服务器才能被外网访问,应用服务器只能内网访问。

模板引擎是一个将页面模板和要显示的数据结合起来生成html页面的工具。如果说express中的路由控制方法相当于MVC中的控制器,那么模板引擎相当于MVC中的视图。

模板引擎的使用

下面两行代码设置模板文件的存储位置和使用的模板引擎

app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

通过调用res.render()渲染模板,将其产生的页面直接返回给客户端,接收两个参数一个是模板名称,views目录下的模板文件名,拓展名.ejs可选。第二个参数是传递给模板的数据对象,用于模板翻译。
routes/index.js

router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});

get请求路径的时候使用{ title: 'Express' }渲染views目录下的模板index模板,把渲染后的数据返回给客户端。其实就是把一个对象传递给了index.ejs文件,得到一个html字符串,把html字符串返回给了前端。

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
  </head>
  <body>
    <h1><%= title %></h1>
    <p>Welcome to <%= title %></p>
  </body>
</html>

restful设计规范

restful-api是目前比较成熟的api设计理念。

域名

api的根入口点应尽可能保持足够简单,例如
api.example.com/(子域名下)
example.com/api/
(主域名下)
域名应该考虑拓展性,如果不确定API后续是否会拓展,应该将其放在子域名下,这样可以保持一定的灵活性。

路径

路径又称为端点,表示API的具体地址路径设计遵循下面约定:

  1. 明明必须全部小写
  2. 资源(resource)命名必须是名词复数形式
  3. 连字符使用"-"而不是","字符可能会在某些浏览器或屏幕中被部分遮挡或全部隐藏
  4. 易读 例如: 反例: api.example.com/getUser api.example.com/addUser 正例: api.example.com/students api.example.com/students/girl...

HTTP请求

对于如何操作资源,有相应的HTTP请求对应,常用有下面5个(括号对应sql语句)

  1. get(select) 从服务器取出一项或者多项资源
  2. post(create)在服务器新建一个资源
  3. put(update)在服务器更新资源(客户端提供改变后的完整资源)
  4. patch(update)在服务器更新资源(客户端提供改变的属性)
  5. delete(delete)从服务器删除资源

下面通过几个简单增删改查demo演示上面的请求

user.js里面

router.get('/', function (req, res, next) {
  res.send('respond with a resource');
  res.json(
    {
      code: 1, msg: "查询成功",
      data: [
        id: 1, username: "zhangsan",
        id: 2, username: "lisan",
      ],
    }
  )
});

Postman中几个body请求格式区别及使用说明

Params与Body

二者区别在于请求参数在http协议中位置不一样。
Params 它会将参数放入url中以?区分以&拼接
Body则是将请求参数放在请求体中

get请求测试

输入地址get请求,选择body然后点击发送请求 15.png 中间很多次不清楚什么原因一直报错,postman返回的消息不是json数据,后来重启了几次注释,开启注释,重新启动,发送get测试成功返回json数据,如果没有语法错误和符号错误,重启服务器可能可以解决这个问题。

16.png

17.png

post请求测试

router.post('/', function (req, res, next) {
  console.log(req.body)//请求的参数
  res.json({
    code: 1,//code1操作成功0操作失败
    msg: '新建成功',
    data: { id: 1, username: "zhangsan" },
  });
});

18.png

19.png

get请求动态id相关信息

一开始多次get请求都是返回404,然后重启服务器就正常了

20.png

patch修改请求

router.patch('/:id', function (req, res, next) {
  // 1.获取参数
  console.log(req.params);
  console.log(req.body)
  // 2.数据库操作
  // 3. 返回json数据
  res.json({
    code: 1,
    msg: "更改成功",
    data: { id: 1, username: "zhangsan" },
  });
});

21.png

删除操作

router.delete('/:id', function (req, res, next) {
  // 1.获取参数
  console.log(req.params);

  // 2.数据库操作
  // 3. 返回json数据
  res.json({
    code: 1,
    msg: "删除成功",
  });
});

(删除请求postman中可以不添加password那个参数,虽然这个测试只是一个小demo)

22.png