express 框架基础和 EJS 模板
一、express 简单使用
- express 是一个基于 Node.js 平台的极简、灵活的 WEB 应用开发框架,官方网址:https://www.expressjs.
com.cn/ - 简单来说,express 是一个封装好的工具包,封装了很多功能,便于我们开发 WEB 应用(HTTP 服务)
-
新建一个文件夹,并初始化 npm,并安装 express
npm init npm i express
-
在文件夹中新建 index.js 文件
// 1. 导入 express const express = require('express');// 2. 创建应用对象 const app = express();// 3. 创建路由,请求方法是 get,请求路径是 /home 时 // 将会调用回调函数 app.get('/home', (req, res) => {res.end('hello express'); });// 4. 监听端口,启动服务 app.listen(9000, () => {console.log('服务已经启动,9000端口监听中...'); });
-
运行项目(如果 index.js 内容有修改,需要重新启动项目,nodemon 可以解决这个问题,可以自行安装)
# 或者 nodemon index.js node index.js
-
在浏览器中输入
127.0.0.1:9000/home
,可以看到效果
二、路由
- 官方定义: 路由确定了应用程序如何响应客户端对特定端点的请求
(一)路由的使用
- 一个路由的组成有
请求方法
,路径
和回调函数
组成 - express 中提供了一系列方法,可以很方便的使用路由,使用格式如下:
app.<method>(path,callback)
const express = require('express');const app = express();// 浏览器输入:http://127.0.0.1:9000/
app.get('/', (req, res) => {res.end('home');
});// post 可以通过发送一个表单请求进行测试
app.post('/login', (req, res) => {res.end('登录成功');
});// 请求方法不限制,只要请求路径一致即可
// 浏览器输入:http://127.0.0.1:9000/test
app.use('/test', (req, res) => {res.end('test');
});// 匹配所有请求, Express5 已经不支持如下写法
// app.all('*', (req, res) => {
// res.end('404 Not Found');
// });// Express5
app.all('{*splat}', (req, res) => {// 将捕获路径值console.log(req.params.splat);res.end('404 Not Found');
});app.listen(9000, () => {console.log('服务已经启动,9000端口监听中...');
});
(二)获取请求参数
-
express 框架封装了一些 API 来方便获取请求报文中的数据,并且兼容原生 HTTP 模块的获取方式
const express = require('express');const app = express();// 浏览器中输入:http://127.0.0.1:9000/request?a=1&b=2#foot app.get('/request', (req, res) => {// 原生获取方式console.log(req.method); // GETconsole.log(req.url); // /request?a=1&b=2console.log(req.httpVersion); // 1.1console.log(req.headers);// express 操作console.log(req.path); // /requestconsole.log(req.query); // { a: '1', b: '2' }console.log(req.ip); // 127.0.0.1// 获取请求头console.log(req.get('host')); // 127.0.0.1:9000res.end('request ok'); });app.listen(9000, () => {console.log('服务启动成功,9000端口监听中...'); });
(三)获取路由参数
-
路由参数指的是 URL 路径中的参数(数据)
const express = require('express');const app = express();// 浏览器中输入:http://127.0.0.1:9000/1234/5678.html app.get('/:id/:code.html', (req, res) => {res.send('商品详情, 商品 id 为' + req.params.id + ',code 为' + req.params.code ); });app.listen(9000, () => {console.log('服务启动成功,9000端口监听中...'); });
三、express 响应设置
- express 框架封装了一些 API 来方便给客户端响应数据,并且兼容原生 HTTP 模块的获取方式
const express = require('express');const app = express();app.get('/response', (req, res) => {// 原生响应// res.statusCode = 404// res.statusMessage = 'not found123'// res.setHeader('abc', 'cba')// res.write('response ok\r\n')// res.end('response ok2')// express 响应// res.status(500); // 设置响应状态码// res.set('aaa', 'bbb'); // 设置响应头// res.send('中文不乱码'); // 设置响应体// 等同于res.status(500).set('aaa', 'bbb').send('中文不乱码');//其他响应// res.redirect('http://baidu.com'); //重定向// res.download('./package.json'); //下载响应// res.json({ name: '张三', age: 18 }); //响应 JSON// res.sendFile(__dirname + '/02.form.html'); //响应文件内容
});
app.listen(9000, () => {console.log('服务启动成功,9000端口监听中...');
});
四、express 中间件
(一)基础
【1】什么是中间件
- 中间件(Middleware)本质是一个回调函数
中间件函数
可以像路由回调一样访问请求对象
(request),响应对象
(response)
【2】中间件的作用
中间件
的作用 就是 使用函数封装公共操作
,简化代码
(二)中间件的类型
中间件分为:全局中间件,路由中间件
【1】全局中间件
- 每一个请求到达服务端之后都会执行全局中间件函数
const express = require('express');const app = express();// 定义一个中间件
function recordMiddleware(req, res, next) {console.log(`记录日志,请求url:${req.url},请求ip:${req.ip}`);next();
}// 应用中间件
app.use(recordMiddleware);app.get('/home', (req, res) => {res.send('home');
});app.get('/login', (req, res) => {res.send('login');
});app.listen(9000, () => {console.log('服务器启动成功,端口9000监听中...');
});
【2】路由中间件
-
如果 只需要对某一些路由进行功能封装 ,则就需要路由中间件
const express = require('express');const app = express();// 生命中间件 function checkCodeMiddleware(req, res, next) {const code = req.query.code;// 判断 code 是否等于 521if (code === '521') {// 如果 code 等于 521,则调用 next() 方法,将请求转发给下一个中间件// 如果没有下一个中间件则调用对应路由的回调next();} else {res.send('code 错误');} }// 使用路由中间件 app.get('/home', checkCodeMiddleware, (req, res) => {// 中间件执行了 next 方法才会进入到该回调函数res.send('home'); });app.get('/admin', checkCodeMiddleware, (req, res) => {res.send('后台首页'); });app.listen(9000, () => {console.log('服务器启动成功,端口9000监听中...'); });
【3】静态资源中间件
- express 内置处理静态资源的中间件
注意事项:
- index.html 文件为默认打开的资源
- 如果静态资源与路由规则同时匹配,谁先匹配谁就响应
- 路由响应动态资源,静态资源中间件响应静态资源
const express = require('express');const app = express();// 设置静态资源中间件
// __dirname + '/public' 是静态资源所在的文件夹
// 如果public 文件夹中 /css/base.css 文件存在
// 在浏览器上直接输入 http://127.0.0.1:9000/css/base.css
// 可以访问到该文件
app.use(express.static(__dirname + '/public'));// 如果请求url 为 http://127.0.0.1:9000/index.html
// public 文件夹中有 index.html 文件
// 该路由也可以响应 /index.html
// 这时候,会响应 public/index.html 文件,
// 因为 静态资源中间件 在路由前面
app.get('/index.html', (request, response) => {response.send('首页');
});app.listen(9000, () => {console.log('服务器启动成功,端口9000监听中...');
});
(三)获取请求体数据 body-parser
- express 可以使用 body-parser 包处理请求体
-
安装 body-parser
npm i body-parser
-
使用 body-parser,新建 index.js 文件
const express = require('express'); const bodyParser = require('body-parser');const app = express();// 解析 JSON 格式的请求体的中间件 // const jsonParser = bodyParser.json();// 解析 querystring 格式请求体的中间件 const urlencodedParser = bodyParser.urlencoded({ extended: false });// 显示登录页面 // 浏览器中输入:http://127.0.0.1:9000/login app.get('/login', (request, response) => {// 将登录页面发送给浏览器response.sendFile(__dirname + '/form.html'); });// 登录页面提交数据的位置 app.post('/login', urlencodedParser, (request, response) => {// urlencodedParser 中间件会将请求体中的数据放置在request.bodyconsole.log(request.body); // { username: 'admin', password: '123456' }response.send('登录成功'); });app.listen(9000, () => {console.log('服务启动成功,端口9000监听中...'); });
-
index.js 文件所在目录新建 form.html 文件
<form action="http://localhost:9000/login" method="post"><label> 用户名:<input type="text" name="username" /> </label><label> 密码: <input type="password" name="password" /> </label><input type="submit" value="提交" /> </form>
五、Router
- 什么是 Router
- express 中的 Router 是一个完整的中间件和路由系统,可以看做是一个小型的 app 对象。
- Router 作用
- 对路由进行模块化,更好的管理路由
-
新建 homeRouter.js 文件,放置所有路由
const express = require('express'); // 创建路由器对象 const router = express.Router();// 在 router 对象身上添加路由 router.get('/', (req, res) => {res.send('get home'); });router.get('/cart', (req, res) => {res.send('get cart'); });// 导出 router module.exports = router;
-
homeRouter.js 文件所在文件夹中,新建 index.js 文件,作为入口文件,并引入 homeRouter.js 文件
const express = require('express');const app = express();// 引入子路由文件 const homeRouter = require('./homeRouter'); // 设置和使用中间件 app.use(homeRouter);app.listen(9000, () => {console.log('9000 端口启动....'); });
六、EJS 模板引擎
(一)基础
【1】 什么是模板引擎
- 模板引擎是分离 用户界面和业务数据 的一种技术
【2】什么是 EJS
- EJS 是一个高效的 Javascript 的模板引擎
- 官网: https://ejs.co/
- 中文站:https://ejs.bootcss.com/
(二)使用
【1】基础语法
-
在项目中安装 EJS
npm i ejs --save
-
创建 index.js 文件,在 js 中使用 ejs 中的语法
const ejs = require('ejs'); const fs = require('fs');// 字符串渲染 let result = ejs.render('我的名字是<%= name %>', { name: '张三' }); console.log(result);// 列表渲染 const list = ['水浒传', '三国演义', '西游记', '红楼梦']; let result2 = ejs.render(`<ul><% list.forEach(item => { %><li><%= item %></li><% }) %></ul>`,{ list } ); console.log(result2);// 条件渲染 const flag = 2; let result3 = ejs.render(`<% if(flag === 1){ %><h1>欢迎回来</h1><% } else if(flag === 2){ %><h1>请登录</h1><% } else { %><h1>请注册</h1><% } %>`,{ flag } );console.log(result3);// 读取 html 文件,并替换里边的数据 const str = fs.readFileSync('./ejs.html'); const html = ejs.render(str.toString(), { name: '李四', list: list, flag }); console.log(html); // <p>我的名字是 李四</p>
-
在 index.js 文件同目录下创建 ejs.html 文件,用于在 html 文件中显示ejs语法
<p>我的名字是 <%= name%></p><ul><% list.forEach(item => { %><li><%= item %></li><% }) %> </ul><% if(flag === 1){ %> <h1>欢迎回来</h1> <% } else if(flag === 2){ %> <h1>请登录</h1> <% } else { %> <h1>请注册</h1> <% } %>
【2】在 express 中使用 ejs
-
安装 ejs 和 express
npm i express npm i ejs --save
-
创建 index.js 文件,进行配置
const express = require('express'); const path = require('path');const app = express();// 将模板引擎设置为 ejs app.set('view engine', 'ejs');// 设置模板文件的存放位置 app.set('views', path.resolve(__dirname, './views'));// 浏览器中输入:http://localhost:9000/home app.get('/home', (req, res) => {// 渲染模板文件// res.render(模板文件名, 对应的数据)res.render('home', {title: '首页'}); });app.listen(9000, () => {console.log('服务启动成功,9000端口监听中...'); });
-
在index.js 文件所在的文件夹中,创建 views 文件夹,用于存放模板文件
-
在 views 文件夹中创建 home.ejs 模板文件
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head> <body><h2><%= title %></h2> </body> </html>
七、express-generator 工具
- 通过应用生成器工具 express-generator 可以快速创建一个应用的骨架。
- https://www.expressjs.com.cn/starter/generator.html
-
全局安装 express-generator
npm install -g express-generator
-
使用如下命令,在某个文件夹中创建项目
express -e 文件夹名称
-
进入到项目所在文件夹,安装依赖
npm i
-
使用如下命令启动项目,由 package.json 可以看到入口文件是 bin/www 文件
npm run start
-
在浏览器中输入
http://localhost:3000/
可以看到项目已经运行了
八、处理文件上传
-
安装 formidable
# 也需要安装 ejs 和 express npm i formidable
-
新建 index.js 文件,用于处理上传的文件所存放的位置
const express = require('express'); const { formidable } = require('formidable'); const path = require('path');const app = express(); const router = express.Router(); // 设置静态资源中间件:设置静态资源目录 app.use(express.static(__dirname + '/public'));// 设置模板引擎 ejs app.set('view engine', 'ejs'); app.set('views', path.resolve(__dirname, './views'));router.get('/', (req, res) => {// 渲染 views/form.ejs 文件res.render('form'); });router.post('/upload', (req, res) => {// 创建 form 对象const form = formidable({multiples: true,// 设置上传文件的报错目录uploadDir: path.resolve(__dirname, './uploads'),// 保持文件后缀keepExtensions: true,});// 解析请求报文form.parse(req, (err, fields, files) => {if (err) {next(err);return;}// console.log(fields); // { username: [ 'admin' ], password: [ '123' ] }// console.log(files); // 文件信息// 让用户根据 url 查看自己上传的文件res.send('/uploads/' + files.portrait[0].newFilename);}); });// 应用路由 app.use(router);app.listen(9000, () => {console.log('9000 端口启动....'); });
-
新建 views 文件夹,并在其中新建 form.ejs 模板文件
<formaction="http://localhost:9000/upload"method="post"enctype="multipart/form-data"><label> 用户名:<input type="text" name="username" /> </label><label> 密码:<input type="password" name="password" /> </label><label> 头像: <input type="file" name="portrait" /> </label><input type="submit" value="提交" /></form>
-
新建 public 文件夹,并在其中新建 uploads 文件夹,用于存放用户提交的文件