目录
- 1、express 介绍
- 2、express 使用
- 2.1 express 下载
- 2.2 express 初体验
- 3、express 路由
- 3.1 什么是路由
- 3.2 路由的使用
- 3.2.1使用Ajax发送一次post请求
- 3.3 获取请求参数
- 3.4 获取路由参数
- 3.5 路由参数练习
- 4、express 响应设置
- 5、express 中间件
- 5.1 什么是中间件
- 5.2 中间件的作用
- 5.3 中间件的类型
- 5.4 全局中间件
- 5.4.1定义全局中间件
- 5.4.2 多个全局中间件
- 5.4.3 具体实现全局中间件
- 5.5 路由中间件
- 5.5.1 定义路由中间件
- 5.6 静态资源中间件
- 5.6.1 静态资源中间件练习
- 5.7 获取请求体数据 body-parser
- 5.7.1 练习
- 6、防盗链
- 6.1 什么是防盗链
- 6.2 防盗链的实现
- 6.3 具体实现
- 7、Router
- 7.1 什么是 Router
- 7.2 Router 作用
- 7.3 Router 使用
- 8、EJS 模板引擎
- 8.1 什么是模板引擎
- 8.2 什么是 EJS
- 8.3 EJS 初体验
- 8.4 EJS 常用语法
- 8.5 EJS 渲染列表
- 8.6 ejs条件渲染
- 8.7 express中使用ejs
- 9、Express 应用程序生成器
1、express 介绍
- express 是一个基于 Node.js 平台的极简、灵活的 WEB应用开发框架,官方网址:https://www.expressjs.com.cn/
- 简单来说,express 是一个封装好的工具包,封装了很多功能,便于我们开发 WEB 应用(HTTP 服务)
大家都应该玩过我的世界,在我的世界中如果纯靠手去砍树或者挖矿,效率是很低的,所以我们在玩的时候会去做个斧头和⛏子,然后再去砍树和挖矿,这样提高了获取资源的效率。
我们开发web应用也是如此,如果纯靠原生去开发,效率是很低的,所以我们就需要用到一些框架来辅助我们提高开发效率。
2、express 使用
2.1 express 下载
-
express 本身是一个 npm 包,所以可以通过 npm 安装
-
先让文件夹初始化为一个『包』, 交互式创建 package.json 文件。
npm init
-
安装express包
npm i express
2.2 express 初体验
- 大家可以按照这个步骤进行操作:
- 创建 JS 文件,输入如下代码
//1、导入包
const express = require('express')
//2、创建应用对象
const app= express()
//3、创建路由规则
app.get('/home', (req, res) => {
res.end('Hello Express')
})
//4、监听端口 启动服务
app.listen(9000,()=>{
console.log('服务已启动,监听9000端口中');
})
- 命令行下执行该脚本
node <文件名>
# 或者
nodemon <文件名>
-
然后在浏览器就可以访问
http://127.0.0.1:9000/home
3、express 路由
3.1 什么是路由
-
官方定义:
路由确定了应用程序如何响应客户端对特定端点的请求
简单来说就是浏览器发送了请求,然后路由决定这个请求由谁去处理;
它会根据请求的路径来决定哪个回调函数去执行。
3.2 路由的使用
-
一个路由的组成有
请求方法
,路径
和回调函数
组成 -
express 中提供了一系列方法,可以很方便的使用路由,使用格式如下:
app.<method>(path,callback)
代码示例:
//1、导入包
const express = require('express')
//2、创建应用对象
const app = express()
//3、创建路由规则
//创建get路由
app.get('/home', (req, res) => {
res.end('Hello Express')
})
// 首页路由
app.get('/', (req, res) => {
res.setHeader('content-type', 'text/html;charset=utf-8')
res.end('网站首页')
})
// 创建post路由
app.post('/login', (req, res) => {
res.end('登录成功')
})
// 创建匹配所有的请求方法
app.all('/search', (req, res) => {
res.setHeader('content-type', 'text/html;charset=utf-8')
res.end('我爱你')
})
//自定义 404 路由
app.all('*', (req, res) => {
res.end('404 Not Found')
})
//4、监听端口 启动服务
app.listen(9000, () => {
console.log('服务已启动,监听9000端口中');
})
3.2.1使用Ajax发送一次post请求
由于浏览器默认发送的是
GET
请求,所以我们需要用Ajax
发送post
请求。当然用form表单也可以发送post请求。
代码示例:
1.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>
button {
width: 60px;
height: 30px;
background-color: aqua;
cursor: pointer;
border: none;
}
</style>
</head>
<body>
<button class="post"></button>
<script>
document.querySelector('.post').addEventListener('click', () => {
const xhr = new XMLHttpRequest()
xhr.open("POST", " http://127.0.0.1:9000/login")
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && /^2\d{2}$/.test(xhr.status)) {
console.log(xhr.responseText)
}
}
xhr.send()
})
</script>
</body>
</html>
2.使用express框架
// 导入express包
const express = require('express')
//导入cors包
const cors = require('cors')
// 创建应用对象
const app = express()
// 调用cors包解决跨域问题
app.use(cors())
// 设置路由规则
app.post('/login',(req,res)=>{
res.end('登录成功')
})
// 监听端口,启动服务
app.listen(9000,()=>{
console.log('服务已启动,监听9000端口中......');
})
3.3 获取请求参数
- express 框架封装了一些 API 来方便获取请求报文中的数据,并且兼容原生 HTTP 模块的获取方式
//导入 express
const express = require('express')
//创建应用对象
const app = express()
//获取请求的路由规则
app.get('/path', (req, res) => {
//1. 获取报文的方式与原生 HTTP 获取方式是兼容的
// 获取请求方法
console.log(req.method);
//获取url
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.headers);
// 获取指定的请求头
console.log(req.get('host'));
res.end('hello')
})
// 监听端口,启动服务
app.listen(9000, () => {
console.log('服务已启动,监听端口9000中.....');
})
3.4 获取路由参数
- 路由参数指的是
URL 路径中的参数(数据)
// 导入express包
const express = require('express')
// 创建应用对象
const app = express()
// 设置路由规则
// :id占位符
app.get('/:id', (req, res) => {
res.setHeader('content-type', "text/html;charset=utf-8")
res.end(`商品详情,商品的id为${req.params.id}`)
})
// params用来存储所有的路由参数
// 监听端口,启动服务
app.listen(9000, () => {
console.log('服务已启动,监听9000端口中......');
})
3.5 路由参数练习
- 要求:根据路由参数响应歌手的信息
路径结构如下
/singer/1.html
显示歌手的`姓名`和`图片`
//json文件
{
"singers": [
{
"singer_name": "周杰伦",
"singer_pic": "http://y.gtimg.cn/music/photo_new/T001R150x150M0000025NhlN2yWrP4.webp",
"other_name": "Jay Chou",
"singer_id": 4558,
"id": 1
},
{
"singer_name": "林俊杰",
"singer_pic": "http://y.gtimg.cn/music/photo_new/T001R150x150M000001BLpXF2DyJe2.webp",
"other_name": "JJ Lin",
"singer_id": 4286,
"id": 2
},
{
"singer_name": "G.E.M. 邓紫棋",
"singer_pic": "http://y.gtimg.cn/music/photo_new/T001R150x150M000001fNHEf1SFEFN.webp",
"other_name": "Gloria Tang",
"singer_id": 13948,
"id": 3
},
{
"singer_name": "薛之谦",
"singer_pic": "http://y.gtimg.cn/music/photo_new/T001R150x150M000002J4UUk29y8BY.webp",
"other_name": "",
"singer_id": 5062,
"id": 4
}
]
}
- 代码实现:
// 导入express包
const express = require('express')
//导入json文件
const { singers } = require('./singers.json')
// 创建应用服务
const app = express()
// 设置路由规则
app.get('/singer/:id.html', (req, res) => {
let { id } = req.params
let result = singers.find(item => {
if (item.id === Number(id)) {
return true
}
})
if (!result) {
req.statusCode = 404
res.end('404 Not Found')
return
}
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>
<div>${result.singer_name}</div>
<div><img src="${result.singer_pic}" alt=""></div>
</body>
</html>`)
})
//监听端口,启动服务
app.listen(9000, () => {
console.log('服务已启动,监听9000端口中.....');
})
4、express 响应设置
- express 框架封装了一些 API 来方便给客户端响应数据,并且兼容原生 HTTP 模块的获取方式
// 导入express包
const express = require('express')
// 创建应用对象
const app = express()
// 设置路由规则
app.get('/response', (req, res) => {
/*
// 1. express 中设置响应的方式兼容 HTTP 模块的方式
// 设置状态码
res.statusCode = 404
// 设置响应状态码描述
res.statusMessage = 'I love you'
// 设置响应头
res.setHeader('server','Node.js')
// 设置响应体
res.write('I love love love ')
res.end(`hello response`) */
//2. express 的响应方法
// 设置响应状态码
/* res.status(404)
// 设置响应头
res.set('server','Node.js')
// 设置响应体
res.send('I love you 我爱你') */
//send会自动加上Content-Type: text/html; charset=utf-8解决中文乱码问题
// 这些方法可以进行连贯操作
res.status(404).set('server','Node.js').send('I love you 我爱你')
//3. 其他响应
})
// 监听端口,启动服务
app.listen(9000, () => {
console.log('服务已启动,监听9000端口中......');
})
- 其他响应
// 导入express包
const express = require('express')
const path = require('path')
// 创建应用对象
const app = express()
// 设置路由规则
app.get('/response', (req, res) => {
//其他响应
// 1.重定向也称//跳转响应
// res.redirect('http://baidu.com')
//2.下载响应
// res.download(path.resolve(__dirname + '/1.html'))
//3.响应JSON
/* res.json({
name: '张三',
age: 18
}); */
//4.响应文件内容
res.sendFile(path.resolve(__dirname + '/1.html'))
})
// 监听端口,启动服务
app.listen(9000, () => {
console.log('服务已启动,监听9000端口中......');
})
5、express 中间件
5.1 什么是中间件
中间件(Middleware)本质是一个回调函数
中间件函数
可以像路由回调一样访问请求对象(request)
,响应对象(response)
5.2 中间件的作用
中间件的作用
就是使用函数封装公共操作,简化代码
5.3 中间件的类型
- 全局中间件
- 路由中间件
5.4 全局中间件
每一个请求
到达服务端之后都会执行全局中间件函数
5.4.1定义全局中间件
- 声明中间件函数
let recordMiddleware = function(request,response,next){
//实现功能代码
//.....
//执行next函数(当如果希望执行完中间件函数之后,仍然继续执行路由中的回调函数,必须调用next)
next();
}
- 应用中间件
app.use(recordMiddleware);
- 声明时可以直接将匿名函数传递给
use
app.use(function (request, response, next) {
console.log('定义第一个中间件');
next();
})
5.4.2 多个全局中间件
- express 允许使用 app.use() 定义多个全局中间件
app.use(function (request, response, next) {
console.log('定义第一个中间件');
next();
})
app.use(function (request, response, next) {
console.log('定义第二个中间件');
next();
})
5.4.3 具体实现全局中间件
// 导入express包
const express = require('express')
const path = require('path')
const fs = require('fs')
// 创建应用对象
const app = express()
// 声明全局中间件函数
function recordMiddleware(req, res, next) {
// 记录url和ip
let { url, ip } = req;
//将信息保存在文件中 access.log日志里面
fs.appendFileSync(path.resolve(__dirname + '/access.log'), `${new Date().toLocaleString()} ${url} ${ip}\r\n`)
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>404NotFound</h1>')
})
// 监听端口,启动服务
app.listen(9000, () => {
console.log('服务已启动,监听9000端口中......');
})
5.5 路由中间件
- 如果 只需要
对某一些路由进行功能封装
,则就需要路由中间件
5.5.1 定义路由中间件
- 要求:针对
/admin /setting
的请求, 要求URL 携带 code=521 参数
, 如未携带提示『暗号错误』
- 具体实现:
//导入 express
const express = require('express');
//创建应用对象
const app = express();
//创建路由
app.get('/home', (req, res) => {
res.send('前台首页');
});
//声明路由中间件
function routeMiddleware(req, res, next) {
if (req.query.code === '521') {
next()
} else {
res.send('暗号错误')
}
}
//后台
app.get('/admin', routeMiddleware, (req, res) => {
res.send('后台首页');
});
//后台设置
app.get('/setting', routeMiddleware, (req, res) => {
res.send('设置页面');
});
app.all('*', (req, res) => {
res.send('<h1>404 Not Found</h1>')
})
//监听端口, 启动服务
app.listen(9000, () => {
console.log('服务已经启动, 端口 3000 正在监听中....')
})
5.6 静态资源中间件
- express 内置处理静态资源的中间件
//引入express框架
const express = require('express');
//创建服务对象
const app = express();
//静态资源中间件的设置,将当前文件夹下的public目录作为网站的根目录
app.use(express.static('./public')); //当然这个目录中都是一些静态资源
//如果访问的内容经常变化,还是需要设置路由
//但是,在这里有一个问题,如果public目录下有index.html文件,单独也有index.html的路由,
//则谁书写在前,优先执行谁
app.get('/index.html',(request,response)=>{
respsonse.send('首页');
});
//监听端口
app.listen(3000,()=>{
console.log('3000 端口启动....');
});
注意事项:
1.index.html 文件为默认打开的资源
2.如果静态资源与路由规则同时匹配,谁先匹配谁就响应
3.路由响应动态资源,静态资源中间件响应静态资源
5.6.1 静态资源中间件练习
-
要求:局域网内可以访问
品优购
的网页 -
品优购项目在我主页的资源里可以下载。
-
文件目录
代码实现://导入 express const express = require('express'); //创建应用对象 const app = express(); //设置静态资源中间件 app.use(express.static(__dirname + '/shoping')); //一句话搞定 //监听端口, 启动服务 app.listen(3000, () => { console.log('服务已经启动, 端口 3000 正在监听中....') })
只要在同一个局域网里都可以访问,不过要知道你本机的
IP地址
是多少。
我的IP地址是192.168.154.16
如手机访问:192.168.154.16:3000
就可以了,大家可自行测试。
5.7 获取请求体数据 body-parser
- 获取请求体数据
body-parser
- 第一步:安装
npm i body-parse
- 第二步:导入 body-parser 包
const bodyParser = require('body-parser');
- 第三步:获取中间件函数
//处理 querystring 格式的请求体
let urlParser = bodyParser.urlencoded({extended:false}));
//处理 JSON 格式的请求体
let jsonParser = bodyParser.json();
- 第四步:设置路由中间件,然后使用
req.body
来获取请求体数据
app.post('/login', urlParser, (req,res)=>{
//获取请求体数据
//console.log(req.body);
//用户名
console.log(req.body.username);
//密码
console.log(req.body.userpass);
response.send('获取请求体数据');
});
- 获取到的请求体数据:
[Object: null prototype] { username: 'admin', userpass: '123456' }
5.7.1 练习
- 要求:
* 按照要求搭建 HTTP 服务
* GET /login 显示表单网页
* POST /login 获取表单中的『用户名』和『密码』
- 代码实现:
// 导入express包
const express = require('express')
// 导入path模块
const path = require('path')
// 导入body-parser包
const bodyParser = require('body-parser')
//解析 JSON 格式的请求体的中间件
// const jsonParser = bodyParser.json()
//解析 querystring 格式请求体的中间件
const urlencodedParser = bodyParser.urlencoded({ extended: false })
// 创建应用对象
const app = express()
// 设置get路由规则
app.get('/login', (req, res) => {
// res.send('表单页面')
//响应 HTML 文件内容
res.sendFile(path.resolve(__dirname + '/1.html'))
})
//设置post路由规则
app.post('/login', urlencodedParser, (req, res) => {
//获取 用户名 和 密码
console.log(req.body);
res.send('获取用户的数据')
});
// 监听端口,启动服务
app.listen(9000, () => {
console.log('服务已启动,监听端口9000中.....');
})
6、防盗链
6.1 什么是防盗链
防盗链其实就是采用服务器端编程,通过url过滤技术实现的防止盗链的软件。
- 比如:xxxxxxxxxxxxx 这个下载地址,如果没有装防盗链,别人就能轻而易举的在他的网站上引用这个地址。
6.2 防盗链的实现
- 要实现防盗链,我们就必须先理解盗链的
实现原理
,提到防盗链的实现原理就不得不从HTTP协议说起,在HTTP协议中,有一个表头字段叫referer
,采用URL的格式来表示从哪儿链接到当前的网页或文件。 - 换句话说,通过
referer
,网站可以检测目标网页访问的来源网页,如果是资源文件,则可以跟踪到显示它的网页地址。 - 有了referer跟踪来源就好办了,这时就可以通过技术手段来进行处理,一旦检测到来源不是本站即进行阻止或者返回指定的页面
6.3 具体实现
//导入 express
const express = require('express');
//创建应用对象
const app = express();
//声明中间件
app.use((req, res, next) => {
//检测请求头中的 referer 是否为 127.0.0.1
//获取 referer
let referer = req.get('referer');
console.log(referer);
if(referer){
//实例化,得到referer的url
let url = new URL(referer);
console.log(url);
//获取 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'));
//监听端口, 启动服务
app.listen(9000, () => {
console.log('服务已经启动, 端口 9000 正在监听中....')
})
7、Router
7.1 什么是 Router
- express 中的 Router 是一个完整的中间件和路由系统,可以看做是一个小型的 app 对象。
7.2 Router 作用
- 对路由进行模块化,更好的管理路由
7.3 Router 使用
- 创建独立的 JS 文件(homeRouter.js)
//1. 导入 express
const express = require('express');
//2. 创建路由器对象
const router = express.Router();
//3. 在 router 对象身上添加路由
router.get('/', (req, res) => {
res.send('首页');
})
router.get('/cart', (req, res) => {
res.send('购物车');
});
//4. 暴露
module.exports = router;
- 主文件
const express = require('express');
const app = express();
//5.引入子路由文件
const homeRouter = require('./routes/homeRouter');
//6.设置和使用中间件
app.use(homeRouter);
app.listen(3000,()=>{
console.log('3000 端口启动....');
})
8、EJS 模板引擎
8.1 什么是模板引擎
- 模板引擎是分离
用户界面和业务数据 的一种技术
。 - 简单来说就是:
分离HTML和JS
注:
分离的是服务端的JS而不是浏览器端的JS
8.2 什么是 EJS
- EJS 是一个高效的 Javascript 的模板引擎
- 官网: https://ejs.co/
- 中文站:https://ejs.bootcss.com/
8.3 EJS 初体验
-
下载安装EJS
npm i ejs --save
代码示例:
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>
//<%= %> 是ejs解析内容的标记,作用是输出当前表达式的执行结构
<h2>我爱你 <%= china %></h2>
<p><%= weather %></p>
</body>
</html>
`js文件`
//1. 安装 EJS
//2. 导入 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);
8.4 EJS 常用语法
-
执行JS代码
<% code %>
-
输出转义的数据到模板上
<%= code %>
-
输出非转义的数据到模板上
<%- code %>
8.5 EJS 渲染列表
- js文件
// 导入ejs包
const ejs = require('ejs')
//西游记
const xy = ['唐僧', '孙悟空', '猪八戒', '沙僧'];
/* // 原生js渲染
let str = `<ul>`
xy.forEach(item => {
str += `<li>${item}</li>`
})
str += '</ul>'
console.log(str); */
// ejs渲染
/* let html = ejs.render(`
<ul>
<% xy.forEach(item=>{%>
<Li><%= item%></Li>
<%})%>
</ul>`,{xy})
console.log(html); */
//外链HTML文件ejs实现
const fs = require('fs');
let html = fs.readFileSync('./02.html').toString()
let result = ejs.render(html, { xy })
console.log(result);
- 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>
<ul>
<% xy.forEach(item=>{%>
<Li>
<%= item%>
</Li>
<%})%>
</ul>
</body>
</html>
8.6 ejs条件渲染
- 要求:
* 通过 isLogin 决定最终的输出内容
* true 输出『<span>欢迎回来</span>』
* false 输出『<button>登录</button> <button>注册</button>』
-
代码实现:
-
js文件
// 导入ejs包
const ejs = require('ejs')
const fs = require('fs')
let isLogin = true
/* // 原生js渲染
if (isLogin) {
console.log(`<span>欢迎回来</span>`);
} else {
console.log(`<button>登录</button> <button>注册</button>`);
} */
// ejs实现
/* let html = ejs.render(`
<%if(isLogin) {%>
<span>欢迎回来</span>
<%}else {%>
<button>登录</button> <button>注册</button>
<%}%>
`,{isLogin:isLogin})
console.log(html); */
// 外链HTML ejs实现
let body = fs.readFileSync('./03.html').toString()
let html = ejs.render(body,{isLogin:isLogin})
console.log(html);
- 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>
<%if(isLogin) {%>
<span>欢迎回来</span>
<%}else {%>
<button>登录</button> <button>注册</button>
<%}%>
</body>
</html>
8.7 express中使用ejs
- js文件
//导入 express
const express = require('express');
//导入 path
const path = require('path');
//创建应用对象
const app = express();
//1. 设置模板引擎
app.set('view engine', 'ejs');// pug twing
//2. 设置模板文件存放位置 模板文件: 具有模板语法内容的文件
app.set('views', path.resolve(__dirname, './view'));
//创建路由
app.get('/home', (req, res) => {
//3. render 响应
// res.render('模板的文件名', '数据');
//声明变量
let title = '云翔集团 - 让天下没有难学的技术';
res.render('home', {title});
//4. 创建模板文件
});
//监听端口, 启动服务
app.listen(9000, () => {
console.log('服务已经启动, 端口 9000 正在监听中....')
})
- 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>
9、Express 应用程序生成器
-
通过应用生成器工具 express-generator 可以快速创建一个应用的骨架。
-
详情介绍官网里面都有:https://www.expressjs.com.cn/starter/generator.html