Express 框架是对 node.js 中 http 模块的封装,可以让我们更好的进行服务相关的开发。
基本使用
一、安装包
npm i express
二、使用
// 1. 导入 express
const express = require('express')
// 2. 创建应用
const app = express()
// 3. 创建路由
app.get('/login', (req, res) => {
// 获取请求路径
console.log(req.path)
// 获取请求参数
console.log(req.query) Express 框架是对 node.js 的封装,可以让我们更好的进行开发。 基本使用 一、安装包 二、使用 express 框架封装了一些获取请求报文跟设置响应报文的方法,但是它也兼容原生的方法。
// 获取请求ip地址
console.log(req.ip)
// 获取请求头
console.log(req.get('host'))
// 获取请求头需要使用第三方的包
// 设置响应状态码
res.status(500)
// 设置响应头
res.set('a', 'b')
// 设置响应体,send 方法已经对字符集进行了设置,所以不会出现乱码的情况
res.send('服务已经启动了')
})
// 所有的路由都可以匹配,一般用来配置访问不存在的路由时的返回
app.all('*', (req, res) => {
res.send('404 Not Found')
})
// 4. 启动服务
app.listen(8000, () => {
console.log('服务已经启动了...')
})
express 框架封装了一些获取请求报文跟设置响应报文的方法,同时它也兼容原生的方法。
特殊的响应
const express = require('express')
const app = express()
app.get('/login', (req, res) => {
// 重定向响应
res.redirect('/admin')
// json 响应,传入一个对象,响应的是一个 json 格式数据
res.json({ name: 'kobe' })
// 下载响应
res.download(__dirname + '/index.html')
// 文件内容响应,相当于直接返回文件
res.sendFile(__dirname + '/index.html')
})
app.listen(8000, () => {
console.log('服务已经启动了...')
})
路由参数
某些情况下我们需要让路由的部分路径来动态显示,同时我们希望能够获取到这个动态路由的数据,具体操作如下
const express = require('express')
const app = express()
// 在路径中通过 :变量名 的方式来设置动态路由
app.get('/login/:id.js', (req, res) => {
// 通过 req.params 属性来获取所有的路由参数
console.log(req.params.id)
res.send('登录')
})
app.listen(8000, () => {
console.log('服务已经启动了...')
})
中间件
本质上是一个用来实现某个功能的函数。
- 全局中间件:所有的路由回调函数在执行之前都会执行的中间件函数。
- 路由中间件:只有指定的路由回调函数在执行之前会执行的中间件函数。
// 定义中间件函数
function record(req, res, next) {}
// 全局使用中间件
app.use(record)
// 指定路由使用中间件
app.get('/login', record, (req, res) => {
res.send('login')
})
静态资源中间件
之前我们做过静态资源访问的模块,Express 封装了对应的中间件,让我们可以直接使用。
// 创建静态资源中间件函数,将当前文件夹下的 public 目录作为网站的根目录
const staticMw = express.static(path.resolve(__dirname, './public'))
// 全局使用
app.use(staticMw)
静态资源中间件不仅帮我们拼接了路径,还帮我们做了 mime 类型处理。
静态资源一般是文件类型,动态资源一般是数据。
注:
- 当我们设置了静态资源的中间件时,会将 public 目录下的 index.html 文件作为默认打开的资源。
http://localhost:8000 --> http://localhost:8000/index.html
2. 如果静态资源跟路由对同一个路径进行了匹配,以书写在前的来匹配。
const staticMw = express.static(path.resolve(__dirname, './public'))
app.use(staticMw)
app.get('/', (req, res) => {
res.send('首页')
})
-
一般用静态资源中间件来响应静态资源文件,用路由来响应动态资源。
-
静态资源请求只能以 get 方式发送。
获取 post 请求体数据的中间件
前面我们展示了获取请求报文的一些方法(见基本使用),但是没有讲到如何获取请求体中的数据。如果我们想要获取到 post 请求体中的数据,需要使用第三方的 body-parser 包来实现。
// 1. 安装包
npm install body-parser
// 2. 导入 body-parser 包
const bodyParser = require('body-parser')
// 3. 获取中间件函数
// 处理 JSON 格式数据的中间件
const jsonParser = bodyParser.json()
// 处理 querystring 格式数据的中间件
const urlencodedParser = bodyParser.urlencoded({ extended: false })
// 4. 设置为路由中间件
app.post('/login', urlencodedParser, (req, res) => {
// 在 req 的 body 属性中就可以访问到请求体的数据
console.log(req.body)
res.send('login')
})
防盗链中间件
静态资源及路由的匹配规则
静态资源跟路由都是用来对发送到服务端的请求进行响应。它们的区别在于,静态资源一般用来响应文件,它的请求路径一般为文件后缀名形式;路由一般用来响应数据,它的请求路径就是普通的 url 。
在服务端我们针对这两种不同形式的 url 有不同的处理方式,那么问题来了,我们在服务端怎么去区分这两种 url 呢?
答案就是不用进行区分。
如果我们在服务端没有配置静态资源的目录,那么在请求时服务端就会根据请求路径去路由规则里匹配,匹配到就执行路由回调函数,匹配不到就返回 404。
如果在服务端配置了静态资源目录(一般都会配置),这时我们会根据书写在前的代码去进行匹配,如果匹配成功就直接执行操作,如果没有匹配到就去另外一个里面匹配,匹配成功就执行操作,匹配不到则返回 404
路由模块化
当页面中存在多个路由时,为了代码的可读性及可维护性,我们会将路由代码拆封为单独的模块来进行开发。
原代码如下:
const express = require('express')
const path = require('path')
const app = express()
// 设置静态资源中间件
app.use(express.static(path.resolve(__dirname, './public')))
// 设置路由
app.get('/login', (req, res) => {
res.send('login')
})
app.all('*', (req, res) => {
res.send('404 Not Found')
})
// 监听端口
app.listen(8000, () => {
console.log('服务已经启动了...')
})
我们将 login 路由相关的代码拆封后如下:
在 login.js 中
const express = require('express')
// 创建路由对象
const router = express.Router()
// 设置路由
router.get('/login', (req, res) => {
res.send('login')
})
// 导出路由对象
module.exports = router
在原文件中:
const express = require('express')
const path = require('path')
// 导入路由对象
const router = require('./login')
const app = express()
// 设置静态资源中间件
app.use(express.static(path.resolve(__dirname, './public')))
// 使用路由对象
app.use(router)
app.all('*', (req, res) => {
res.send('404 Not Found')
})
app.listen(8000, () => {
console.log('服务已经启动了...')
})
ejs 模板引擎
模板引擎
众所周知,我们是无法在一个 HTML 模板中直接使用 JavaScript 中定义的变量的。
<body>
<script>
const uname = 'kobe'
</script>
<h2> uname </h2> // 不能使用
<h2> ${ uname } </h2> // 不能使用
</body>
所以我们一般是通过 JavaScript 来实现模板跟变量的拼接。
但是这样会存在一些问题,例如在 JavaScript 文件中书写模板很不方便,以及模板跟变量之间的耦合性太强。这时候我们就可以使用模板引擎。
模板引擎就是用来将 HTML 结构跟 JavaScript 代码分离开的。模板引擎一般适用于服务端。
ejs 模板引擎的基本使用
// 1. 安装 ejs
npm i ejs
01.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>
<h2>
<!-- ejs 语法,通过这种方式来使用变量 -->
<%= uname %>
</h2>
</body>
</html>
js 文件
// 导入文件读取模块
const fs = require('fs')
// 2. 导入 ejs
const ejs = require('ejs')
//3. 定义在 html 文件中使用的变量
const uname = 'kobe'
// 4. 读取html文件
const html = fs.readFileSync('./01.html').toString()
// 5. 使用 ejs 来渲染
const result = ejs.render(html, { uname })
console.log(result)
列表渲染跟条件渲染
<!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>
<ul>
<!-- 列表渲染 -->
<% list.forEach(item => { %>
<li><%= item %></li>
<% }) %>
</ul>
<!-- 条件渲染 -->
<% if(flag) {%>
<p>登录</p>
<% } else { %>
<p>注册</p>
<% } %>
</body>
</html>
js 文件
// 导入文件读取模块
const fs = require('fs')
// 2. 导入 ejs
const ejs = require('ejs')
//3. 定义在 html 文件中使用的变量
const list = ['kobe', 'james', 'caohan']
const flag = true
// 4. 读取html文件
const html = fs.readFileSync('./01.html').toString()
// 5. 使用 ejs 来渲染
const result = ejs.render(html, { list, flag })
console.log(result)
在 Express 中使用 ejs 模板引擎
我们在使用 Express 创建服务时有时会返回一个页面,这个时候就可以使用模板引擎。
不使用模板引擎的情况:
const express = require('express')
const app = express()
app.get('/login', (req, res) => {
// 直接返回页面
res.sendFile(__dirname + '/index.html')
})
app.listen(8000, () => {
console.log('服务已经启动了...')
})
使用模板引擎返回页面的情况:
// 在 Express 框架中对模板引擎已经做了集成,可以直接使用
const express = require('express')
const path = require('path')
const app = express()
// 1. 设置模板引擎使用的类型为 ejs
app.set('view engine', 'ejs')
// 2. 设置模板文件的存放位置为当前目录的 views 文件夹下
app.set('views', path.resolve(__dirname, './views'))
app.get('/login', (req, res) => {
// 定义变量
const title = '登录页'
// 3. express 会去 views 文件夹下查找对应名称的 .ejs 文件,将变量传入后渲染,然后返回
res.render('index',{ title })
})
app.listen(8000, () => {
console.log('服务已经启动了...')
})
在 ./views/index.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>
<!-- 使用变量 -->
<h2><%= title %></h2>
</body>
</html>
Express 应用程序生成器
通过应用生成器工具 express-generator 可以快速创建一个应用的骨架。
处理文件上传
处理文件上传我们需要用到一个第三方的库 formidable
我们可以通过 form 表单来上传文件
<form action="/file" method="post" enctype="multipart/form-data">
<input type="text" name="username" />
<input type="file" name="upload" />
</form>
在路由文件中
const express = require('express')
// 1. 导入 formidable
const formidable = require('formidable')
const router = express.Router()
// 文件上传的路由
router.post('/file', (req, res) => {
// 2. 创建 form 对象
const form = formidable({
multiples: true,
// 设置上传文件的保存目录为静态资源文件夹下的 images 目录
uploadDir: __dirname + '/../public/images',
// 保持文件的后缀名
keepExtensions: true,
})
// 3. 解析请求报文
form.parse(req, (err, fields, files) => {
if (err) {
next(err)
return
}
// 4. 获取文件的地址,后续保存到数据库中
const fileURL = '/images/' + files.upload.newFilename
res.send()
})
})
// 导出路由对象
module.exports = router