express框架简介

express是一款基于Node.js平台,快速、开放、极简的web开发框架。

官网:https://www.expressjs.com.cn/

express安装配置

express是node的第三方框架
初始化:npm init
安装: npm i express
使用的时候引入即可:const express = require("express")

express使用

res.send

之前都是用
res.write()
res.end()
向前端页面写数据,但是比较麻烦,一般情况下我们还需定义
res.writeHead(200, { "Content-Type":}),还需要注意返回的书html片段,页面还是json数据,比较麻烦。
EXPRESS框架直接将这些内容封装成res.send(),我们可以直接将数据进行返回,比较方便。

  • 返回html片段:
    res.send(`
    <html>
        <h1>Hello World</h1>
    </html>
    `)

在这里插入图片描述

  • 返回json字符串
    直接写成对象即可,无需严格安装json数据的格式来。
    res.send({
        name: "yang",
        age:18
    })

在这里插入图片描述

  • 补充
    res.send()可以送html片段或数据
    res.json()只能送数据
    res.render()只能送模板(整个html页面)

创建服务器

const express = require("express")
const app = express()
app.listen(3000, () => {
    console.log("server start")
})

处理路径

固定路径

const express = require("express")
const app = express()

app.get("/", (req, res) => {
    res.write("hello")
    res.end()
})

app.listen(3000, () => {
    console.log("server start")
})

在这里插入图片描述

字符串路径

  • ? 表示可选
    eg:
app.get("/abc?d", (req, res) => {
    res.send("ok")
})

表示可以匹配 /abcd/abd 路径

  • : 表示占位符(携带变量)
    eg:
app.get("/ab/:id", (req, res) => {
    res.send("ok")
})

:id是一个占位符
表示可以匹配 /ab/XXX (XXX可以是任何内容)路径

  • + 表示该字符可以重复1-n次
    eg:
app.get("/ab+c", (req, res) => {
    res.send("ok")
})

表示可以匹配 /abbc/abc 等b是1-n个的路径

  • * 表示该字符可以是任意字符
app.get("/a*c", (req, res) => {
    res.send("ok")
})

表示可以匹配 /abc/a1c 等路径

  • (),可以将多个字符结合成一个整体
    eg:
app.get("/a(bc)?d", (req, res) => {
    res.send("ok")
})

表示可以匹配 /abcd/ad 等路径

正则表达式路径

  • 任何含有a的路径:
//匹配任何路径中含有a的路径:
app. get(/a/,function(req,res) {
    res. send(' /a/');
});
  • 匹配以fly结尾的路径:
app.get(/.*fly$/,function(req,res) {
    res.send('/a/');
});

路径的匹配规则

请求路径(路由或ajax请求)和express中间件的路径匹配分为两种,一种是使用app.use匹配,另一种是使用app.getapp.post匹配。其中使用app.use匹配的是按照部分匹配的,而不是完全匹配。而使用app.getapp.post的是完全匹配。

  • 完全匹配规则
    只有路径一模一样才会进行匹配
  • 部分匹配规则:
    当请求到达服务器时,Express 会按照中间件的定义顺序依次匹配路径。只要请求路径以中间件的路径开头并且请求路径的长度要大于等于中间件的路径长度就会匹配成功,即中间件会被执行。而不管请求路径是否与中间件的路径完全一致。
    同时一个请求路径可以被多次匹配,但是前提是匹配到的中间件执行了 next(),如果没有执行next() 就只会被匹配一次。
  • 案例1:
app.use('/users/:id', (req, res, next) => {
  console.log('Middleware 2');
  next();
});

app.use('/users', (req, res, next) => {
  console.log('Middleware 1');
  next();
});
  • 请求路径:/users/1234
    输出:
:Middleware 2
 Middleware 1
  • 请求路径:/users
    输出:
 Middleware 1
  • 案例2:
    即使将两个中间件的位置调换也是同样的输出,说明中间件的先后顺序没有严格要求。
补充:express的路由路径的匹配规则

express 有自己的路由插件:

var router = express.Router();

该路由插件的路由路径的匹配是完全匹配,即请求路径必须与路由路径完全匹配才会执行对应的路由处理函数。

  • 案例1
const router = express.Router();

router.get('/users', (req, res) => {
  console.log('Matched /users');
});

router.get('/users/:id', (req, res) => {
  console.log('Matched /users/:id');
});
  • 请求路径:/users/1234
    输出:
Matched /users/:id
  • 请求路径:/users
    输出:
Matched /users

路由匹配的先后顺序也没有严格要求。

回调函数(中间件)

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

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

普通中间件

app.get的第一个参数是路由,第二个参数就是回调函数(中间件)了。
express的可以有多个回调函数,前一个回调函数通过next()来执行下一个回调函数。

eg:

app.get("/home", (req, res, next) => {
    console.log("验证token")
    next()
}, (req, res) => {
    res.send({list:[1,2,3]})
})

app.listen(3000, () => {
    console.log("server start")
})

也可以写成数组的样式,代码更整洁:

const func1 = (req, res, next) => {
    console.log("验证token")
    next()
}
const func2 = (req, res) => {
    res.send({list:[1,2,3]})
}

app.get("/home",[func1,func2])

app.listen(3000, () => {
    console.log("server start")
})

中间件(回调函数)之间的数据传递:通过res,req公共参数进行值传递。
eg:

const func1 = (req, res, next) => {
    console.log("验证token")
    res.valueF1 ="我是func1中的值"
    next()
}
const func2 = (req, res) => {
    console.log(res.valueF1)
    res.send({list:[1,2,3]})
}

app.get("/home",[func1,func2])
app.listen(3000, () => {
    console.log("server start")
})

输出:

验证token
我是func1中的值

应用级中间件—挂在app上

将所有请求功能公有的,都要执行的回调函数提取出,封装成应用级中间件。
使用app.use(公共回调函数名)
这样每个请求都会先执行该函数
eg:

const express = require("express")
const app = express()

const func1 = (req, res, next) => {
    console.log("验证token")
    res.valueF1 ="我是func1中的值"
    next()
}
app.use(func1)
const func2 = (req, res) => {
    console.log(res.valueF1)
    res.send({list:[1,2,3]})
}

app.get("/home",[func2])
app.get("/list", (req, res) => {
    res.send("list")
})
app.listen(3000, () => {
    console.log("server start")
})

注意应用级别的中间件定义的位置。

  • app.use可以有其他参数
    eg:app.use("/home",func1)表示只对/home请求执行func1中间件

路由级中间件—挂在router上

router/indexRouter.js

const express = require("express")

const router = express.Router()

// 路由级别中间件
router.get("/home", (req, res) => {
    res.send("home")
})
router.get("/login", (req, res) => {
    res.send("login")
})

module.exports = router

路由级别中间件的调用:(利用应用级别中间件进行调用)

const express = require("express")
const app = express()
const indexRouter = require("./router/indexRouter")

const func1 = (req, res, next) => {
    console.log("验证token")
    res.valueF1 ="我是func1中的值"
    next()
}
// 应用级别中间件
app.use( func1)
// 应用级别中间件
app.use("/", indexRouter)
app.listen(3000, () => {
    console.log("server start")
})

我们经常这样用:app.use("/api/", indexRouter)
那么访问路径就是:http://localhost:3000/api/login

为了逻辑清晰可以将不同功能的请求放在不同的不同的路由文件中。

错误处理中间件

错误处理中间件和其他中间件定义类似,只是要使用4个参数,而不是3个,其签名如下: (err, req, res, next),当然也可以不用。

eg:

app.use((req, res) => {
    res.status(404).send("出错了")
})

注: 直接使用send返回,状态码默认是200

第三方中间件

安装所需功能的node模块,并在应用中加载,可以在应用级加载,也可以在路由级加载。

app.use/app.get/app.post的第一个参数问题

app.use: 可以接受post和get请求
app.get: 可以接受get请求
app.post: 可以接受post请求

有一个问题是:如果路径匹配的时候,他们的第一个参数的匹配的到底是路由地址还是请求地址?
即可以匹配路由地址,又可以匹配请求地址,

Express获取前端传过来的数据

获取get请求的参数

get请求携带的参数直接携带在请求后面。
在node中直接通过 req.query就可以获取传过来的参数。
eg:
(1)入口:index.js

const express = require("express")
const app = express()
const indexRouter = require("./router/indexRouter")

const func1 = (req, res, next) => {
    console.log("验证token")
    res.valueF1 ="我是func1中的值"
    next()
}
// 应用级别中间件
app.use( func1)
// 应用级别中间件
app.use("/api/", indexRouter)

app.use((req, res) => {
    res.status(404).send("出错了")
})
app.listen(3000, () => {
    console.log("server start")
})

(2)入口:indexRouter.js

const express = require("express")

const router = express.Router()

// 路由级别中间件
router.get("/home", (req, res) => {
    res.send("routerhome")
})
router.get("/login", (req, res) => {
    console.log(req.query)
    res.send("routerlogin")
})

module.exports = router

访问:http://localhost:3000/api/login?username=yang
终端输出:

验证token
{ username: 'yang' }

获取post请求的参数

在express中,post请求需要使用 xx.post 来接收。
post请求的参数放在请求体中,在express中使用req.body来获取传递过来的参数。
但是使用req.body必须配置中间件,用于解析post参数:

  • 在请求开始配置:app.use(express.urlencoded({extended:false}))
    该配置只能处理form编码格式的数据,即:username='yang'&password='123456‘
  • 在请求开始配置:
    app.use(express.json())
    该配置用于处理json数据,即:
    {"name":"yang","password":"123456"}

eg:
(1)入口:index.js

const express = require("express")
const app = express()
const indexRouter = require("./router/indexRouter")

// 配置解析post参数,不用下载第三方,内置
app.use(express.json())//处理post参数:{"name":"yang","password":"123456"}
app.use(express.urlencoded({ extended: false }))//处理post参数:username='yang'&password='123456

const func1 = (req, res, next) => {
    console.log("验证token")
    res.valueF1 ="我是func1中的值"
    next()
}
// 应用级别中间件
app.use(func1)
// 应用级别中间件
app.use("/api/", indexRouter)

app.use((req, res) => {
    res.status(404).send("出错了")
})
app.listen(3000, () => {
    console.log("server start")
})

(2) indexRouter.js:

const express = require("express")

const router = express.Router()

// 路由级别-响应get请求
router.get("/home", (req, res) => {
    res.send("routerhome")
})

// 路由级别-响应get请求
router.get("/login", (req, res) => {
    console.log(req.query)
    res.send("routerlogin")
})

// 路由级别-响应post请求
router.post("/login", (req, res) => {
    console.log(req.body)
    //使用req.body必须配置中间件,解析post参数的中间件,在请求开始配置
    res.send({
        ok:1
    })
})

module.exports = router

验证:
发送post请求可以使用FeHelper的Postman功能进行发送:
在这里插入图片描述

  • 发送from格式的参数
    在这里插入图片描述
    控制台
    在这里插入图片描述
  • 发送json格式参数:
    在这里插入图片描述

Express托管静态资源

通过Express内置的expres.static可以方便地托管静态文件,例如图片、CSS、JavaScript 文件等。
将静态资源文件所在的目录作为参数传递给express.static中间件就可以提供静态资源文件的访问了。
例如,假设在public目录放置了图片、CSS 和JavaScript文件,就可以:
app.use(express.static('public'))
这样,public 目录下面的文件就可以访问了。

并且可以设置多个静态资源。

eg:
(1) public/login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    Login
</body>
</html>

(2) index.js

const express = require("express")
const app = express()
const indexRouter = require("./router/indexRouter")


// 配置静态资源
app.use(express.static("public"))

// 配置解析post参数,不用下载第三方,内置
app.use(express.json())//处理post参数:{"name":"yang","password":"123456"}
app.use(express.urlencoded({ extended: false }))//处理post参数:username='yang'&password='123456

const func1 = (req, res, next) => {
    console.log("验证token")
    res.valueF1 ="我是func1中的值"
    next()
}
// 应用级别中间件
app.use(func1)
// 应用级别中间件
app.use("/api/", indexRouter)

app.use((req, res) => {
    res.status(404).send("出错了")
})
app.listen(3000, () => {
    console.log("server start")
})

indexRouter.js

const express = require("express")

const router = express.Router()

// 路由级别-响应get请求
router.get("/home", (req, res) => {
    res.send("routerhome")
})

// 路由级别-响应get请求
router.get("/login", (req, res) => {
    console.log(req.query)
    res.send("routerlogin")
})

// 路由级别-响应post请求
router.post("/login", (req, res) => {
    console.log(req.body)
    //使用req.body必须配置中间件,解析post参数的中间件,在请求开始配置
    // app.use(express.urlencoded({extended:false}))
    res.send({
        ok:1
    })
})

module.exports = router

启动index.js
访问:http://localhost:3000/login.html
在这里插入图片描述

小案例:实现登录功能

登陆成功时后跳转到home页面

目录结构:
在这里插入图片描述

(1)静态资源

  • public/css/home.css
.title{
    background-color: brown;
}
  • public/home.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 这里不是路径是请求 -->
    <link rel="stylesheet" href="/css/home.css">
    
</head>
<body>
    Home
    <div class="title">欢迎回来</div>
</body> 
</html>
  • public/login.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link rel="stylesheet" href="/css/login.css" />
  </head>
  <body>
    Login
    <div>
      <div>
        用户名:
        <input type="text" id="username" />
      </div>
      <div>
        密码:
        <input type="password" id="password" />
      </div>
      <div>
        <button type="submit" id="login">登录-get</button>
        <button type="submit" id="loginpost">登录-post</button>
      </div>
    </div>

    <script type="text/javascript">
      var login = document.querySelector("#login");
      var loginpost = document.querySelector("#loginpost");
      var username = document.querySelector("#username");
      var password = document.querySelector("#password");

      //   get请求
      login.onclick = () => {
        fetch(
          `/api/login?username=${username.value}&password=${password.value}`
        )
          .then((res) => res.text())
          .then((res) => {
            console.log(res)
             if(res=="routerlogin"){
                // 跳转页面
                location.href ="home.html"
            }else{
                alert("用户名密码不对")
            }
          });
      };

      //   post请求
      loginpost.onclick = () => {
        fetch(`/api/login`, {
          method: "POST",
          body: JSON.stringify({
            username: username.value,
            password: password.value,
          }),
          headers: {
            "Content-Type": "application/json",
          },
        })
          .then((res) => res.text())
          .then((res) => {
            console.log(res)
            res = JSON.parse(res)
            if(res.ok==1){
                // 跳转页面
                location.href ="home.html"
            }else{
                alert("用户名密码不对")
            }
          });
      };
    </script>
  </body>
</html>

(2) node后端

  • 入口:index.js
const express = require("express")
const app = express()
const indexRouter = require("./router/indexRouter")
const router = require("./router/router")

// 配置静态资源
app.use(express.static("public"))

// 配置解析post参数,不用下载第三方,内置
app.use(express.json())//处理post参数:{"name":"yang","password":"123456"}
app.use(express.urlencoded({ extended: false }))//处理post参数:username='yang'&password='123456

const func1 = (req, res, next) => {
    console.log("验证token")
    next()
}
// 应用级别中间件
app.use(func1)

// 应用级别中间件
app.use("/api/", indexRouter)

app.use("/login", router)

app.use((req, res) => {
    res.status(404).send("出错了")
})
app.listen(3000, () => {
    console.log("server start")
})
  • indexRouter.js
const express = require("express")

const router = express.Router()

// 路由级别-响应get请求
router.get("/home", (req, res) => {
    res.send("routerhome")
})

// 路由级别-响应get请求
router.get("/login", (req, res) => {
    const { username, password } = req.query
    if (username === 'yang' && password === '123456') {
        res.send("routerlogin")
    } else {
        res.send("登录失败")
    }
})

// 路由级别-响应post请求
router.post("/login", (req, res) => {
    const {username,password} = req.body
    //使用req.body必须配置中间件,解析post参数的中间件,在请求开始配置
    // app.use(express.urlencoded({extended:false}))

    if (username === 'yang' && password === '123456') {
        res.send({
            ok:1
        })
    } else {
        res.send({
            ok:0
        })
    }
})

module.exports = router
  • router.js
const express = require("express")
const fs = require("fs")
const mime = require("mime")
const path =require("path")

const router = express.Router()

// 路由级别-响应get请求
router.get("/", (req, res) => {
    res.writeHead(200, {  "Content-Type": "text/html;charset=utf-8" })
    res.write(fs.readFileSync("C:/Users/86198/VScode/qianDuan/Node/express/public/login.html"), "utf-8")
    res.end()
})

module.exports = router

实现效果
在这里插入图片描述
登陆成功,跳转到home页面
在这里插入图片描述
登陆失败弹出警告框:
在这里插入图片描述

EXPRESS服务端渲染

两种开发方法

服务器渲染

后端嵌套模板,后端渲染模板,SSR (后端把页面组装)
a. 前端做好静态页面,动态效果。
b. 前端将代码提供给后端,后端要把静态html以及里面的假数据给删掉,
通过模板动态生成html的内容

  • 优点:数据可以显示在网页源码中,有利于爬虫
  • 缺点:前后端容易起冲突

前后端分离

BSR (前端中组装页面)
a. 前端做好静态页面,动态效果。
b. 前端做好 json模拟,ajax,动态创建页面。
c. 真实接口数据,前后联调。
d. 前端提供给后端静态资源文件夹。

  • 优点:前后端分工明确
  • 缺点:数据不能完整显示在网页源码中,爬虫爬不到数据。
    eg:
    前端:home.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 这里不是路径是请求 -->
    <link rel="stylesheet" href="/css/home.css">
    
</head>
<body>
    Home
    <div class="title">欢迎回来</div>
     <ul class="list"></ul>
    <script type='text/javascript'>
    fetch("/api/home/list").then((res) => res.json())
          .then((res)=>{
            console.log(res)
            render(res)
          })
    function render (data){
        // map将数组中的每一个值进行映射
       var list = data.map(item=>`<li>${item}</li>`)
       var oul = document.querySelector(".list")
    //  list.json("")将数据变成字符串 ,解析成节点 
       oul.innerHTML = list.join("")
    }
    
    </script>
</body> 
</html>

后端:

router.get("/home/list", (req, res) => {
    res.send(["111","222","333"])
})

响应结果:
在这里插入图片描述
我们可以发现源码中没有数据:
在这里插入图片描述

服务器渲染开发模式——EJS模板

ejs的下载使用

  • 安装ejs:npm i ejs
  • 设置模板的放置位置:我们一般将模板文件(.ejs)放置在views目录中,所以可以设置: app.set('views', ' ./views')
  • 设置模板引擎view engine: 这里我们使用ejs:
    app.set('view engine', 'ejs')

.ejs文件就是.html文件的写法

可以通过res.render()直接将.ejs页面进行返回。
同时res.render()可以返回参数,供.ejs页面 使用。

ejs的标签含义

  • <%=变量名%> :接受变量,里面可以放置变量名
  • <%%>:表示流程控制标签,里面可以放置 if ,for语句
    被<%%>包住的内容相当于js的代码
  • <%-变量名%> :和<%=变量名%>功能相同,但是如果变量值是一个html代码片段,使用<%-变量名%>会直接解析改代码片段但是<%=变量名%>不会解析
  • <%# %>:注释标签,和 <!---->相比,优点是<%# %>注释是不会被解析到前端的,网页查看源码可以看到<!---->注释但是看不到<%# %>注释

ejs实现登录例子

需求:
通过/login可以访问登陆页面,登录成功后跳转到home页面,否则提示错误
文件目录结构:
在这里插入图片描述
index.js:

const express = require("express")
const app = express()
const loginRouter = require("./router/loginRouter")
const homeRouter = require("./router/homeRouter")
const func1 = (req, res, next) => {
    console.log("验证token")
    next()
}

// 配置模板引擎
app.set('views','./views')
app.set('view engine','ejs')

// 配置静态资源
app.use(express.static("public"))

// 配置解析post参数,不用下载第三方,内置
app.use(express.json())//处理post参数:{"name":"yang","password":"123456"}
app.use(express.urlencoded({ extended: false }))//处理post参数:username='yang'&password='123456

// 应用级别中间件
app.use(func1)

// 应用级别中间件
app.use("/login/", loginRouter)
app.use("/home/", homeRouter)

app.use((req, res) => {
    res.status(404).send("出错了")
})
app.listen(3000, () => {
    console.log("server start")
})

homeRouter.js

const express = require("express")

const router = express.Router()

// 路由级别-响应get请求
router.get("/", (req, res) => {
    var list =["111","222","333"]
    res.render("home", { list: list })
})

module.exports = router

loginRouter.js

const express = require("express")

const router = express.Router()

// 路由级别-响应get请求
router.get("/", (req, res) => {
    // 渲染模板之后返回给前端
    res.render("login",{error:""})//会自动找views下的login.ejs,因为配置了app.set('views', './views')
    
})

// 路由级别-响应post请求
router.post("/", (req, res) => {
    if (req.body.username === 'yang' && req.body.password === '123456') {
        // 重定向到home
        res.redirect("/home")
    } else {
        res.render("login",{error:"用户名密码错误!"})
    }
})

module.exports = router

home.ejs

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    home-页面 
    <ul>
        <%for(var i =0;i<list.length;i++){%>
        <li><%=list[i]%></li>
        <%}%>
    </ul>
</body>
</html>

login.ejs

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    login-页面
    <form action="/login" method="POST">
        <div><input type="text" name="username"></div>
        <div><input type="password" name="password"></div>
        <div><button type="submit">提交</button></div>
    </form>
    <p style="color: red;"><%=error%></p>
    
</body>
</html>

EJS的公共文件

对于多个页面公有的内容,我们可以将这部分内容提取出来写在一个.ejs文件中,用的时候引用就可以了。
引用格式:<%- include(" ejs文件路径") %>
当然也可以传递参数。
eg:<%- include("./header.ejs",{isShowTitle:false}) %>

前后端分离开发模式——使用EJS

前后端分离的开发模式不需要使用.ejs文件,直接使用html文件
模板引擎配置:

// 配置模板引擎
app.set('views','./views')
app.set('view engine','html')
app.engine("html",require("ejs").renderFile)//支持直接渲染html文件

EXPRESS生成器

通过应用生成器工具express-generator可以快速创建一个应用的骨架。

利用生成器创建express项目过程

  • 安装生成器 npm install -g express-generator
  • 生成项目:express myapp(项目名) --view=ejs
    –view=ejs表示使用ejs格式生成项目。
    生成结果:
    在这里插入图片描述
  • 安装依赖:跳转到myapp目录,执行npm i
  • 运行项目:查看package.json找到项目入口
    在这里插入图片描述
    入口是./bin/www,运行start就可以运行项目。
    运行:npm run strat

访问:http://localhost:3000/
在这里插入图片描述

生成器创建express项目解析

在这里插入图片描述

(1)bin/www
项目的入口:完成服务器的创建,端口号的监听,错误的提示
(2)app.js

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

var app = express();

// 配置模板引擎
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

// 记录日志
app.use(logger('dev'));

// 配置解析post参数
app.use(express.json());
app.use(express.urlencoded({ extended: false }));

// 对前端的cookie进行解析
app.use(cookieParser());
// 配置静态资源
app.use(express.static(path.join(__dirname, 'public')));

// 中间件
app.use('/', indexRouter);
app.use('/users', usersRouter);

// 错误
app.use(function (req, res, next) {
  // 将错误的具体内容传递个下一个中间件
  next(createError(404));
});

// 错误页面
app.use(function(err, req, res, next) {
  // 将错误信息挂载到res中
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

补充:app.use(cookieParser());的使用

配置cookieParser可以使我们直接访问和设置cookie。
eg:访问http://localhost:3000/users,原本的cookie值
在这里插入图片描述
routers/users.js

var express = require('express');
var router = express.Router();

router.get('/', function (req, res, next) {
  // 读取前端cookie
  console.log(req.cookies)
  // 设置前端cookie
  res.cookie("gender","female")
  res.send('respond with a resource');
});

module.exports = router;

运行代码,再次访问http://localhost:3000/users,
输出:

{
  'Idea-28ab0e0': 'b69f8bd6-22ea-4572-8336-40ed65a8fe24',
  '3AB9D23F7A4B3C9B': 'DZ35O6YOU5HGNKNLCACSM2SN64NDORL7LBZX572332Q6ODCC7VOS55HGBCW6A6YMJSPGPVUCDSVM7474QOUUMBGOKQ',
  PHPSESSID: 'rtc69005r571vj7mavtnmrecuv',
  MANTIS_STRING_COOKIE: '15cdeb236652f03d82a1354249ce5d99cf15e453058d2b30c07bb193e84ae370',
  MANTIS_secure_session: '0',
  io: '1zrrFp5Fm5kgxCHVAAAh'
}

查看浏览器cookie:
在这里插入图片描述

Logo

长江两岸老火锅,共聚山城开发者!We Want You!

更多推荐