一、express介绍
express是一个基于Node.js平台的极简、灵活的WEB应用开发框架,官方网址https://www.expressjs.com.cn/
简单来说,express是一个封装好的工具包,封装了很多功能,便于我们开发WEB应用(HTTP服务)
二、express使用
2.1 express下载
express本身是一个npm包,所以可以通过npm安装
npm i express
2.2 express初体验
// 1.导入express
const express=require('express');
// 2.创建应用对象
const app=express();
// 3.创建路由
app.get('/home',(req,res)=>{
res.end('hello express')
});
// 4.监听端口,启动服务
app.listen(3000,()=>{
console.log('服务已启动...3000端口正在监听');
})
三、express路由
3.1 什么是路由
**官方定义:**路由确定了应用程序如何相应客户端对特定端点的请求
3.2 路由的使用
一个路由的组成由 请求方法,路径和回调函数组成
express中提供了一系列的方法,可以和你方便的使用路由
// 1.导入express
const express=require('express');
// 2.创建应用对象
const app=express();
// 3.创建路由
//get方法请求
app.get('/home',(req,res)=>{
res.end('hello express');
});
//首页路由
app.get('/',(req,res)=>{
res.end('我是首页');
});
//post方法请求
app.post('/login',(req,res)=>{
res.end("login login");
});
//所有方法的请求
app.all('/test',(req,res)=>{
res.end('test test');
});
// 404响应
app.all('*',(req,res)=>{
res.end('404 Not Found');
});
// 4.监听端口,启动服务
app.listen(3000,()=>{
console.log('服务已启动...3000端口正在监听');
});
3.3 获取请求参数
express框架封装了一些API来方便获取请求报文中的数据没并且兼容原生HTTP模块的获取方式
// 导入express
const express=require('express');
// 创建应用对象
const app=express();
// 创建路由
app.get('/request',(req,res)=>{
//原生操作
// 1.获取报文的方式与原生HTTP获取方式是兼容的
console.log(req.method);
console.log(req.url);
console.log(req.httpVersion);
console.log(req.headers);
// 2.express独有的获取报文的方式
console.log(req.path);
//获取查询字符串
console.log(req.query);//相对重要
//获取ip
console.log(req.ip);
// //获取指定的请求头
// console.log(req.get('host'));
res.end('hello express');
});
// 监听端口,启动服务
app.listen(3000,()=>{
console.log('启动成功...');
});
3.4 获取路由参数
路由参数指的是URL路径中的参数(数据)
// 导入express
const express=require('express');
// 创建应用对象
const app=express();
// 创建路由
app.get('/:id.html',(req,res)=>{
res.setHeader('content-type','text/html;charset=utf-8');
res.end('商品详情,商品id为'+req.params.id)
});
// 监听端口,启动服务
app.listen(3000,()=>{
console.log('服务已启动...3000端口正在监听');
});
3.5 歌手案例
{
"singers": [
{
"singer_name": "周杰伦",
"singer_pic": "https://p2.ifengimg.com/2019_20/93F1AA4B254456CF1F06C237E5B95C59E68126B1_w2300_h1724.jpg",
"other_name": "Jay Chou",
"singer_id": 4558,
"id": 1
},
{
"singer_name": "林俊杰",
"singer_pic": "http://y.gtimg.cn/music/photo_new/T001R150x150M000001BLpXF2DyJe2.webp",
"other_name": "Lin",
"singer id": 4286,
"id": 2
},
{
"singer_name": "G.E.M.邓紫棋",
"singer_pic": "https://tse4-mm.cn.bing.net/th/id/OIP-C.1m1ACN9T60PedYwYta0WGAHaHt?w=186&h=194&c=7&r=0&o=5&dpr=2&pid=1.7",
"other_name": "Gloria Tang",
"singer_id": 13948,
"id": 3
}
]
}
// 导入express
const express=require('express');
//导入JSON文件
const {singers}=require('./singers.json');
console.log(singers);
// 创建应用对象
const app=express();
// 创建路由
app.get('/singer/:id.html',(req,res)=>{
//获取路由参数
let {id}=req.params;
//在数组寻找对应id的数据
let result=singers.find(item=>{
if(item.id===Number(id)){
return true;
}
});
if(!result){
res.statusCode=404;
res.end(`<h1>404 Not Found</h1>`);
return;
}
console.log(result);
res.end(`
<!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>
<h3>${result.singer_name}</h3>
<img src='${result.singer_pic}'/ width=300px>
</body>
</html>`)
});
// 监听端口,启动服务
app.listen(3000,()=>{
console.log('服务已启动...3000端口正在监听');
});
四、express 响应设置
express框架封装了一些API来方便给客户端响应数据,并且兼容原生HTTP模块的获取方式
// 导入express
const express=require('express');
// 创建应用对象
const app=express();
// 创建路由
app.get('/response',(req,res)=>{
//原生响应
// res.statusCode=404;
// res.statusMessage='love';
// res.setHeader('xxx','yyy');
// res.write('hello express')
// res.end('rsponse')
//express响应
// res.status(500);
// res.set('aaa','bbb');
// res.send('你好 Express');//不用设置字符集,自动设置了
//连贯操作
res.status(500).set('aaa','sdf').send("这些都是OK的")
});
// 监听端口,启动服务
app.listen(3000,()=>{
console.log('服务已启动...3000端口正在监听');
});
// 导入express
const express=require('express');
// 创建应用对象
const app=express();
// 创建路由
app.get('/other',(req,res)=>{
//跳转响应(重定向)
// res.redirect('http://atguigu.com');
//下载响应
// res.download(__dirname+'/package.json');//单独的语句
//json响应
// res.json({
// name:'尚硅谷',
// slogon:'让天下没有难学的技术'
// });
// res.send('你好 Express');//不用设置字符集,自动设置了
//响应文件内容
res.sendFile(__dirname+'/test.html')
});
// 监听端口,启动服务
app.listen(3000,()=>{
console.log('服务已启动...3000端口正在监听');
});
五、express中间件
5.1 什么是中间件
中间件(Middleware)本质是一个回调函数
中间件函数可以像路由回调一样访问请求对象(request),响应对象(response)
5.2 中间件的作用
中间件的作用就是使用函数封装公共操作,简化代码
5.3 中间件的类型
- 全局中间件
- 路由中间件
5.3.1 定义全局中间件
每一个请求到达服务端之后都会执行全局中间件函数
/**
* 记录每一个请求的URL与Ip地址(服务器的访问日志)
*/
// 导入express
const express=require('express');
const fs=require('fs');
const path=require('path');
// 创建应用对象
const app=express();
//声明中间件函数
function recordMiddleware(req,res,next){
//获取url和Ip
let {url,ip}=req;
//将信息保存在文件中 access.log
fs.appendFileSync(path.resolve(__dirname,'./access.log'), `${url} ${ip}\r\n`);
//调用next
next();
}
//使用中间件函数
app.use(recordMiddleware);
// 创建路由
app.get('/home',(req,res)=>{
res.send('前台首页');
});
app.get('/admin',(req,res)=>{
res.send("后台首页");
});
app.all('*',(req,res)=>{
res.send('<h1>404 Not Found</h1>');
});
// 监听端口,启动服务
app.listen(3000,()=>{
console.log('服务已启动...3000端口正在监听');
});
5.3.2 路由中间件实践
/**
* 针对 /admin /setting的请求,要求携带code=521的参数,如未携带提示 暗号错误
*/
// 导入express
const express=require('express');
// 创建应用对象
const app=express();
// 创建路由
app.get('/home',(req,res)=>{
res.send('前台首页');
});
//声明中间件
let checkCodeMiddleware=(req,res,next)=>{
//判断URL中是否code参数等于521
if(req.query.code==='521'){
next();
}else{
res.send("暗号错误");
}
}
app.get('/admin',checkCodeMiddleware,(req,res)=>{
res.send("后台首页");
});
app.get('/setting',checkCodeMiddleware,(req,res)=>{
res.send("设置页面");
});
app.all('*',(req,res)=>{
res.send('<h1>404 Not Found</h1>');
});
// 监听端口,启动服务
app.listen(3000,()=>{
console.log('服务已启动...3000端口正在监听');
});
5.4 静态资源中间件
// 导入express
const express=require('express');
// 创建应用对象
const app=express();
//静态资源中间件设置,将当前文件夹下的public目录作为网站的根目录
app.use(express.static(__dirname+'/public'));//当然这个目录都是一些静态资源
// 创建路由
app.get('/index.html',(req,res)=>{
res.end('首页');
});
// 监听端口,启动服务
app.listen(3000,()=>{
console.log('服务已启动...3000端口正在监听');
});
注意事项:
- index.html 文件为默认打开的资源
- 如果静态资源与路由规则同时匹配,谁先匹配谁就响应
- 路由响应动态资源,静态资源中间件响应静态资源
5.5 获取请求体数据 body-parse
express可以使用body-parse
包处理请求体
第一步:安装
npm i body-parse
第二步:导入 body-parse包
const bodyParse=require('body-parse');
第三步:获取中间件函数
//处理 querystring 格式的请求体
let urlParser=bodyParser.urlencoded({extended:false});
//处理JSON格式的请求体
let jsonParser=bodyParser.json();
第四步:设置路由中间件,然后使用request.body
来获取请求体数据
/**
* 按照要求搭建HTTP服务
*
* get /login 显示表单网页
* post /login 获取表单中的用户名和用户数据
*/
// 导入 express
const express=require('express');
const bodyParser=require('body-parser');
// 创建应用对象
const app=express();
//解析JSON格式的请求体的中间件
const jsonParser=bodyParser.json()
//解析querystring格式请求体的中间件
const urlencodeParser=bodyParser.urlencoded({extended:false});
//创建路由规则
app.get('/login',(req,res)=>{
// res.send('表单页面')
//响应html 文件内容
res.sendFile(__dirname+'/11_form.html');
});
// post 规则
app.post('/login',urlencodeParser,(req,res)=>{
//获取用户名和密码
console.log(req.body);
res.send('获取用户数据');
});
// 启动服务
app.listen(3000,()=>{
console.log('3000 server is running...');
});
当urlencodeParser中间件执行完毕后会在req上加一个属性body
5.6 图片防盗链
// 导入express
const express=require('express');
// 创建应用对象
const app=express();
//声明中间件
app.use((req,res,next)=>{
//检测请求头中的referer是否为127.0.0.1
//和获取referer
let referer=req.get('referer');
if(referer){
//实例化
let url =new URL(referer);
//获取hostname
let hostname=url.hostname;
//判断
if(hostname!=='127.0.0.1'){
//响应404
res.status(404).send('<h1>404 Not Found</h1>');
return;
}
}
next();
});
//静态资源中间件设置
app.use(express.static(__dirname+'/public'));//相当于根目录root
// 监听端口,启动服务
app.listen(3000,()=>{
console.log('服务已启动...3000端口正在监听');
});
六、 路由模块化
//1.导入express
const express=require('express');
//2.创建路由对象
const router=express.Router();
// 首页
router.get('/home',(req,res)=>{
res.send('前台首页');
});
// 搜索
router.get('/search',(req,res)=>{
res.send('搜索页面');
});
//对外暴露模块
module.exports=router;
//1.导入express
const express=require('express');
//2.创建路由对象
const router=express.Router();
// 后台首页
router.get('/admin',(req,res)=>{
res.send('后台首页');
});
// 设置页面
router.get('/setting',(req,res)=>{
res.send('设置页面');
});
//对外暴露模块
module.exports=router;
// 导入express
const express=require('express');
const homeRouter=require('./routes/homeRouter');
const adminRouter=require('./routes/adminRouter');
// 创建应用对象
const app=express();
//设置
app.use(homeRouter);
app.use(adminRouter);
app.all('*',(req,res)=>{
res.send('<h1>404 Not Found</h1>');
});
// 监听端口,启动服务
app.listen(3000,()=>{
console.log('服务已启动...3000端口正在监听');
});
七、EJS模板引擎
7.1 什么是模板引擎
分离用户界面和业务数据的一种技术(分离HTML与JS的技术,降低耦合)
7.2 什么是EJS
EJS是一种高效的JavaScript的模板引擎
官网:https://ejs.co/
中文站:https://ejs.bootcss.com
7.3 EJS初体验
下载安装EJS
npm i ejs
//导入EJS
const ejs=require('ejs');
const fs=require('fs');
//字符串
let china ='中国';
let weather='今天天气不错~'
//声明变量
let str=fs.readFileSync('./01_html.html').toString();
//声明EJs渲染
let result=ejs.render(str,{china,weather});
console.log(result);
7.4 列表渲染
const ejs=require('ejs');
const xiyou=['唐僧','孙悟空','猪八戒','沙和尚']
// //原生js
// let str='<ul>';
// xiyou.forEach(item=>{
// str+=`<li>${item}</li>`;
// });
//EJS 实现
const fs=require('fs');
let html=fs.readFileSync('./02_西游.html').toString();
let result= ejs.render(html,{xiyou:xiyou});
console.log(result);
<!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>西游四人组</h2>
<ul>
<% xiyou.forEach(item => { %>
<li><%= item %></li>
<% }) %>
</ul>
</body>
</html>
注意:一但模板拼接写错,就会出现SyntaxError: Unexpected token ';' while compiling ejs
的错误
7.5 条件渲染
<% if(isLogin){ %>
<span>欢迎回来</span>
<%}else{%>
<button>登录</button> <button>注册</button>
<% }%>
7.6 express中使用EJS
const express=require('express');
const path=require('path');
//导入express 模块
const app=express();
// 1.设置模板引擎
app.set('view engine','ejs');//pug twing
// 2.设置模版文件存放位置 模板文件:具有模板语法内容的文件
app.set('views',path.resolve(__dirname,'./views'));
// 创建路由
app.get('/home',(req,res)=>{
// 3.render响应
// res.render('模板的文件名','数据');
// 声明变量
let title='捉襟见肘记账本'
res.render('home',{title});
// 4.创建模板文件
});
// 监听端口,启动服务
app.listen(3000,()=>{
console.log('服务已启动,3000端口正在监听中...');
});
<!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>
<h2>哈喽</h2>
</body>
</html>
7.7 Express应用程序生成器
通过应用程序生成器工具express-generator可以快速创建一个应用的骨架。
安装:
npm install -g express-generator
添加ejs模版引擎的支持
express -e 文件夹名称
7.8 文件上传
具体看代码15-generator文件夹中的图片上传
问题1:Error: Cannot find module ‘cookie-parser’
问题产生的原因是:express4里要单独安装cookie-parser和express-session
解决办法:
插入代码块:
npm install express-session --save
或
npm install cookie-parser --save
问题2:formidable not a function
获取包的时候加上{},如下:
const {formidable}=require('formidable');
扩展:lowdb
安装指定版本的lowdb
npm i lowdb@1.0.0
轻量级本地JSON数据库