目录
2.1 什么是路由?路由确定了应用程序如何响应客户端对特定端点的请求
一、express框架初体验
1. 初始化项目 npm i
2. 下载express依赖 npm i express
3. 创建index.js文件
//导入
const express = require('express');
//创建应用对象
const app = express();
//创建路由
//首页
app.get('/', (req, res) => {
//原生操作
// console.log(req.method);
// console.log(req.url)
// console.log(req.httpVersion)
// console.log(req.headers.host)
//express操作
res.end('home')
console.log(req.path)
console.log(req.query)
//获取ip
//console.log(req.ip)
//获取请求头
// console.log(req.get('host'));//127.0.0.1:5000
//提取路由参数
})
app.get('/home', (req, res) => {
res.end('hello')
})
app.post('/login', (req, res) => {
res.end('login')
})
//匹配所有方法
app.all('/test', (req, res) => {
res.end('test');
})
//404响应
app.all('*', (req, res) => {
res.end('404');
})
//监听端口
app.listen(5000,()=>{
console.log('5000端口服务启动...')
})
4. 运行index.js文件 nodemon ./index.js
二、express路由
2.1 什么是路由?路由确定了应用程序如何响应客户端对特定端点的请求
2.2 路由的使用(组成:请求方法,路径,回调函数)
2.3 获取路由参数
路由参数指的是URL路径中的参数。当详情页面很多时,一般使用占位符来替换具体值。
//导入
const express = require('express');
//创建应用对象
const app = express();
//创建路由
//首页 :code 占位符
app.get('/:code.html', (req, res) => {
//获取URL路由参数
let urlCode = req.params.code;
res.setHeader('content-type','text/html;charset=utf-8')
//express操作
res.end('商品:'+urlCode)
//提取路由参数
console.log(urlCode);
})
//监听端口
app.listen(5000,()=>{
console.log('5000端口服务启动...')
})
2.3.1 获取路由参数练习
例 根据给定的json数据展示歌手信息,路径结构 /1.html
singer.json
{
"singers": [
{
"id": 1,
"name":"歌手1"
},
{
"id": 2,
"name":"歌手2"
}]
}
//导入
const express = require('express');
//导入singer json文件
const {
singers
} = require('./static/JSON/singer.json')
//console.log(singers);
//创建应用对象
const app = express();
//创建路由
//首页 :code 占位符
app.get('/:id.html', (req, res) => {
//获取URL路由参数
let {
id
} = req.params;
//在数组中寻找对于id
let result = singers.find(item => {
//item为对象
if (item.id === Number(id)) {
return true;
}
})
//console.log(result);
res.setHeader('content-type', 'text/html;charset=utf-8')
if(!result){
res.statusCode = 404;
res.end(`<h2>404 not found</h2>`)
}
res.end(`
<!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>${id}</h2>
<p>${result.name}</p>
</body>
</html>
`);
})
//监听端口
app.listen(5000, () => {
console.log('5000端口服务启动...')
})
2.4 响应设置
- res.send( ),自动添加 Content-Type: text/html; charset=utf-8
- 可以连贯操作,链式写法。res.status().set().send();
- 重定向响应 res.redirect( )
- 下载响应 res.download( )
- JSON响应 res.json( )
- 响应文件内容 res.sendFile( )
const express = require('express');
//创建应用对象
const app = express();
//创建路由
//首页
app.get('/response', (req, res) => {
//原生响应
// res.statusCode = 201;
// res.statusMessage ='OK!'
// res.setHeader('xxx','yyy')
// res.setHeader('ttt',['aaa','bbb']);
// res.write('hello!')
// res.end('express response');
// res.status(201);
// res.set('header', ['h1', 'h2'])
// res.send('你好 express')
res.status(201).set('header', ['h1', 'h2']).send('你好 express');
})
app.get('/other', (req, res) => {
//其他响应
//重定向
//res.redirect('https://blog.csdn.net/weixin_42152058?spm=1011.2124.3001.5343');
//下载响应
//res.download(__dirname + '/package.json');
//res.status(201).set('header', ['h1', 'h2']).send('你好 express');
//JSON响应
// res.json({
// name:'json',
// msg:'test'
// })
//响应文件内容
res.sendFile(__dirname + '/index.html')
})
//404响应
app.all('*', (req, res) => {
res.end('404');
})
//监听端口
app.listen(5000, () => {
console.log('5000端口服务启动...')
})
三、中间件
- 中间件本质一个回调函数,中间件函数可以向路由回调一样请求对象,响应对象。
- 中间件使用函数封装公共操作,简化代码。
- 两种类型,全局中间件和路由中间件。
- 每个请求到达服务端之后都会执行中间件函数
3.1 全局中间件
- 将一些重复下代码可放到中间件函数中
- 声明中间件函数,res 请求报文的对象,req 响应报文的对象 ,next 内部函数:指向后续的路由回调或中间件回调。 并且一定要调用 next() , 执行后续的路由回调
- 使用中间件函数
例 记录每个请求的url,ip,将信息保存 access.log中。相当于服务器的访问日志,便于查看请求的来源,可以精准的定位问题
const express = require('express');
const app = express();
const fs = require('fs');
const path = require('path')
// 声明中间件函数
function recordMiddle(req, res, next) {
let {
url,
ip
} = req;
console.log(url, ip);
//全局方法
fs.appendFileSync(path.resolve(__dirname, './access.log'), `${url} ${ip} \r\n`);
//调用next
next();
}
//使用中间件函数
app.use(recordMiddle);
//首页
app.get('/home', (req, res) => {
res.status(201).send('前台');
})
app.get('/admin', (req, res) => {
res.status(201).send('后台');
})
//404响应
app.all('*', (req, res) => {
res.send('404');
})
//监听端口
app.listen(5000, () => {
console.log('5000端口服务启动...')
})
3.2 路由中间件
例 针对/admin /setting 的请求,要求携带 code=2023 参数,如未携带则提示 目标错误
const express = require('express');
const app = express();
const fs = require('fs');
const path = require('path');
//中间件
let checkCodeMiddle = (req,res,next)=>{
if(req.query.code === '2023'){
//满足条件调用路由回调
next();
}else{
res.send('目标错误')
}
}
//首页 将中间件添加到受约束的路由规则中,放置路径后
app.get('/home', checkCodeMiddle,(req, res) => {
res.send('前台');
});
app.get('/admin', checkCodeMiddle,(req, res) => {
res.send('后台');
});
app.get('/setting',checkCodeMiddle,(req, res) => {
res.send('后台设置');
});
3.3 静态资源中间件
- 处理静态资源的中间件,通过 app.use(express.static(__dirname + '/static'));
- index.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/index.css">
<script src="./js/index.js"></script>
</head>
<body>
<h2>i</h2>
<p>歌手1</p>
<img src="./img/img1.jpg" alt="" srcset="">
</body>
</html>
const express = require('express');
const app = express();
const fs = require('fs');
const path = require('path');
//防盗链
app.use((req, res, next) => {
//检测请求头中的refer是否为127.0.0.1
//获取referer
let referer = req.get('referer');
//console.log(referer);
if (referer) {
//实例化
let url = new URL(referer);
//获取 hostname
let hostname = url.hostname;
console.log(hostname)
if(hostname !== '127.0.0.1'){
res.statusCode = 404 ;
res.send(`<h2>404</h2>`)
}
}
next();
});
//静态资源中间件设置 express.static()返回一个函数
app.use(express.static(__dirname + '/static'));
//首页 将中间件添加到受约束的路由规则中,放置路径后
app.get('/', (req, res) => {
res.send('前台');
});
app.get('/admin', (req, res) => {
res.send('后台');
});
app.get('/setting', (req, res) => {
res.send('后台设置');
});
//404响应
app.all('*', (req, res) => {
res.send('404');
})
//监听端口
app.listen(5000, () => {
console.log('5000端口服务启动...')
})
3.4 获取响应体数据
例 按照要求搭建HTTP服务
- GET /login 显示表单
- POST /admin 获取表单中的用户名和密码
- npm i body-parser
- 使用body-parser
解析json格式的中间件
const jsonParser = bodyParser.json()
解析querystring格式的中间件
const urlencodedParser = bodyParser.urlencoded({ extended: false })
const express = require('express');
const app = express();
let bodyParser = require('body-parser')
//解析querystring格式的中间件
const urlencodedParser = bodyParser.urlencoded({ extended: false })
//首页
app.get('/login', (req, res) => {
res.sendFile(__dirname+'/login.html')
});
app.post('/login',urlencodedParser,(req, res) => {
//urlencodedParser执行完毕后,向请求对象的身上添加一个属性 body
console.log(req.body);
res.send('后台数据');
});
//404响应
app.all('*', (req, res) => {
res.send('404');
})
//404响应
app.all('*', (req, res) => {
res.send('404');
})
//监听端口
app.listen(5000, () => {
console.log('5000端口服务启动...')
})
<!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>
<form action="/login" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password" id=""><br>
<button>登录</button>
</form>
</body>
</html>
四、 防盗链
//防盗链
app.use((req, res, next) => {
//检测请求头中的referer是否为127.0.0.1
//获取referer
let referer = req.get('referer');
//console.log(referer);
if (referer) {
//实例化
let url = new URL(referer);
//获取 hostname
let hostname = url.hostname;
console.log(hostname)
//主要通过判断请求头中的refefer的host是否为 当前的地址
if(hostname !== '127.0.0.1'){
res.statusCode = 404 ;
res.send(`<h2>404</h2>`)
}
}
next();
});
五、路由模块化
简而言之,即使将路由规则拆分到不同文件,最后在总文件require,并use,这与使用中间件函数一样。
- index.js
const express = require('express');
const router = require('./routers/router')
const admin = require('./routers/admin')
const app = express();
app.use(router);
app.use(admin);
//404响应
app.all('*', (req, res) => {
res.send('404');
})
//监听端口
app.listen(5000, () => {
console.log('5000端口服务启动...')
})
- router.js
const express = require('express');
// 创建路由对象
const router = express.Router();
//创建路由规则
router.get('/home', (req, res) => {
res.send('前台');
});
router.get('/search', (req, res) => {
res.send('搜索');
});
//暴露router
module.exports = router;
- admin.js
const express = require('express');
// 创建路由对象
const router = express.Router();
//创建路由规则
router.get('/admin', (req, res) => {
res.send('后台');
});
router.get('/setting',(req, res) => {
res.send('后台设置');
});
//暴露router
module.exports = router;
六、EJS模板引擎
模板引擎是用户界面和业务数据的一种技术,分离html和js的
6.1 ejs初体验
-
index.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>
<style>
h2 {
background-color: skyblue;
}
img {
width: 200px;
height: 200px;
}
</style>
</head>
<body>
<h2><%= hello%> , <%= str%></h2>
</body>
</html>
-
list.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>批量渲染</h2>
<ul>
<% arry.forEach(item => { %>
<li><%= item %></li>
<% }) %>
</ul>
</body>
</html>
-
check.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>
<header>
<% if(isLogin){ %>
<span>welcome</span>
<% }else{ %>
<button>登录</button> <button>注册</button>
<% } %>
</header>
</body>
</html>
-
test.js
const express = require('express');
const app = express();
const ejs = require('ejs')
const fs = require('fs');
const path = require('path');
app.get('/', (req, res) => {
let hello = 'hello';
let str = 'ejs'
let data = fs.readFileSync('./index.html').toString();
//使用ejs渲染
let result = ejs.render(data, {
str: str,
hello
})
//console.log(result);
res.send(result);
});
//列表渲染
app.get('/list', (req, res) => {
const arry = ['aa', 123, 201, 'test'];
//1.原生js
/*
let ul = '<ul>';
arry.forEach(item => {
ul += `<li>${item}</li>`
})
ul += '</ul>'
console.log(ul)
*/
//2.ejs实现
let data2 = fs.readFileSync('./list.html').toString();
let ul = ejs.render(data2,{arry})
console.log(ul);
res.send(ul);
})
//条件渲染
/**通过isLogin决定最终的输出内容
* true <span>welcome</span>
* false <button>登录</button> <button>注册</button>
*/
app.get('/check', (req, res) => {
let isLogin =true;
let data3 = fs.readFileSync('./check.html').toString();
let result = ejs.render(data3,{isLogin:isLogin})
res.send(result);
})
//404响应
app.all('*', (req, res) => {
res.send('404');
})
//监听端口
app.listen(5000, () => {
console.log('5000端口服务启动...')
})
6.2 express中使用ejs
- 先设置模板引擎,如ejs、pug 、twingdeng
- 设置模板文件存放位置,且路径转成绝对路径
- 调用 res.render(模板的文件名,数据),响应文件内容
- 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>
<h2>ejs测试 <%= str %></h2>
</body>
</html>
- index.js
const express = require('express');
const path = require('path')
const app = express();
//设置模板引擎 pug twing
app.set('view engine','ejs');
//设置模板文件存放位置,存放路径转成绝对路径 具有模板语法内容的文件
app.set('views',path.resolve(__dirname,'./views'))
app.get('/home', (req, res) => {
let str = '模板文件';
//render响应 res.render(模板的文件名,数据)
res.render('home',{str});
})
//监听端口
app.listen(5000, () => {
console.log('5000端口服务启动...')
})