文章目录
-
- 前言
- 1 Express
-
- 1.1 什么是express
- 1.2 为什么需要express
- 1.3 手动安装手动配置
- 2 Express基本使用
-
- 2.1 主要代码及注释
- 3 处理网页
-
- 3.1 处理静态资源
- 3.2 什么是ejs(模板引擎)
-
- 3.2.1 ejs的特点
- 3.2.2 ejs的成员函数
- 3.3.3 ejs的常用标签
- 3.3 处理动态资源
- 在模板中使用数据
- 4 处理路由
-
- 4.1 应用级别中路由
- 4.2 处理路由第二种方式
- 5 会话技术
-
- 5.1 什么是会话?
- 5.2 会话技术
- 5.3 cookie作用
- 5.4 cookie记录上一次访问的时间
- 5.5 session的使用
- 6 Express中间件
-
- 6.1 next介绍
- 6.2 next使用
- 6.3 next正确使用方式
- 6.4 express中间件
- 7 Express脚手架
-
- 7.1 通过express搭建项目
- 7.2 生成的app.js
前言
这部分主要是node使用express框架之后的简写版本。
1 Express
express:表达;快速(这里取快速的翻译)
1.1 什么是express
Express是一个基于NodeJS的Web Server开发框架, 能够帮助我们快速的搭建Web服务器。
1.2 为什么需要express
-
利用原生的NodeJS开发Web服务器,
我们需要处理很多繁琐且没有技术含量的内容。
例如: 获取路由->解析路由->分配路由->处理路由等。
但是有了Express之后, 就能帮助我们省去大量繁琐的环节, 让我们只用关注核心业务逻辑。
-
利用原生的NodeJS开发Web服务器,
我们需要自己手动去实现静态/动态资源处理, get/post参数的解析, cookie的解析, 日志处理等。
但是有了Express之后, 已经有现成的插件帮我们实现了上述功能。
- 所以作为单身的程序猿(媛), 如果你还想留一些时间去约会, 那么Express是你的最佳选择。
1.3 手动安装手动配置
传送门
安装:
npm i express -S
2 Express基本使用
2.1 主要代码及注释
// 导入express
const express = require("express");
// express执行(调用express方法),创建服务端实例对象
const app = express();
// req,res 并不是原生node中的req,res
// 它是在原生node的基本上进行增强
// 虽然此处req,res进行了增强,但是也可以使用原生node中的api
app.get("/",(req,res)=>{//路由 默认是/ 一个地址,对应了一个响应
// res.writeHead(200,{'Content-type':'text/plain;charset=utf-8'})//解决字符乱码问题
// res.end("www.badu.com")//响应数据
//之前的原生方法也能使用
res.send("hello express")
})
app.get("/login",(req,res)=>{ // 一个地址,对应了一个响应
res.send("<h1>登录页面</h1>")
})
//监听端口
app.listen(3000,()=>{//告诉服务端需要监听哪一个端口
console.log("server is running on 3000");
})
res.send([body|status], [body])
既可以直接发送内容,也可以第一个参数状态,第二个参数内容。
如果直接发送内容的话,状态会被自动补全;
详细介绍:传送门
我们向服务器发一个请求,核心有两种请求方式:
1)get请求 偏向于向服务器要数据 当然也可以把数据给服务器
A)浏览器的地址栏就可以发起get请求
B)a标签的href也可以发起get请求
C)link标签的href也可以发起get请求
D)script 标签的 src也可以发起get请求
E)img标签的src也可以发起get请求
F)form表示也可以发起Get表示
…
特点:
1)会数据放到地址栏中 不太安全
2)post请求 偏向于把数据扔给服务器
利用form表示发起get请求:
1)action表示此请求地址
2)method请求的方式
3)表单中的input必须要有一个name属性
<form action="http://localhost:3333/doreg" method="get">
<ul>
<li>用户名:<input type="text" name="username"></li>
<li>密码:<input type="password" name="pwd"></li>
<li><input type="submit" value="注册"></li>
</ul>
</form>
3 处理网页
3.1 处理静态资源
const express = require("express");
const path = require("path")
const app = express();
//可以配置多个静态资源目录
app.use(express.static('public'))
// app.use(express.static('files'))
// app.use('/static', express.static('files'))
========================express托管静态资源
// use 表示使用中间件 express内部自带一个中间件 express.static()
// express.static 此中间件就可以托管静态资源 是一个内置的中间件
// console.log(path.join(__dirname,"public"));
app.use(express.static(path.join(__dirname, 'public')));
项目位置:
3.2 什么是ejs(模板引擎)
ejs
:一个模板引擎,默认情况下,你的模板中写的数据都是假数据,一般数据都是来自于数据库的。如果把数据库中的数据取出来,放到需要
替换数据
的地方,此时就是一个真数据,这个流程叫
服务端渲染
。
3.2.1 ejs的特点
- 快速编译和渲染
- 简单的模板标签
- 自定义标记分隔符
- 支持文本包含
- 支持浏览器端和服务器端
- 模板静态缓存
- 支持express视图系统
3.2.2 ejs的成员函数
Render(str,data,[option]):直接渲染字符串并生成html
str:需要解析的字符串模板
data:数据
option:配置选项
3.3.3 ejs的常用标签
<% %>流程控制标签
<%= %>输出标签(原文输出HTML标签)
<%- %>输出标签(HTML会被浏览器解析)
<%# %>注释标签
% 对标记进行转义
3.3 处理动态资源
模板:就是前端程序员写好的html页面,html页面中的数据默认都是假数据,我们需要把它里面的假数据替换成真实的数据,此时就需要使用模板。一般情况下,是把模板放在views下面的,如下:
原本是
.html
需要换为
.ejs
,也可以用别的方法代替。
在模板中使用数据
var ejs = require("ejs");// 导入ejs模块
==================================路径写法一
app.use(express.static(path.join(__dirname,"public")))
// 1)告诉express,你的模板在什么地方
app.set("views",path.join(__dirname,"views"));//绝对路径的写法
==================================路径写法二
// 把./views目录设置为模板文件根,html文件模板放在view目录中
app.set("views", "./views");//告诉express,模板放在views下面
==============================================================================
// 设置模板引擎为ejs
// 2)告诉express,你使用的模板引擎是什么 ejs 除了ejs模板引擎之外,还有其它的模板引擎
app.set('view engine', 'ejs')
app.get("/xxx",(req,res)=>{
// res.send("hello express")
// 把数据渲染到模板中 通过res.render就可以渲染模板,同时就可以给模板上绑定数据
res.render('xxx',{msg:"dadaima"});
})
<h1>我是一个模板</h1>
<h2><%= msg %></h2>
4 处理路由
4.1 应用级别中路由
const express = require("express");
// app叫应用
const app = express();
app.get("/reg", (req, res) => {
res.send("<h1>注册页面</h1>")
})
app.get("/login", (req, res) => {
res.send("<h1>登录页面</h1>")
})
app.get("/cart", (req, res) => {
res.send("<h1>购物车页面</h1>")
})
app.post('/api/user/register', (req, res, next) => {
res.json({
name: 'xq',
age: 18,
method: 'post'
});
});
app.listen(3000, () => {
console.log("server is running on 3000");
})
注意:
1.响应对象的json方法是express给响应对象扩展的
2.这个方法会自动将对象转换成字符串之后返回
3.这个方法还会自动帮助我们设置响应头
4.2 处理路由第二种方式
在项目的根目录下,创建一个routes文件夹:
不同的模块,有不同的路由文件,这里的
routes
和controller的意思是一样的。
user.js
和
goods.js
里面的路由,叫
二级路由
。
user.js代码如下:
const express = require("express");
// router叫路由对象
const router = express.Router();
// 说白了,就是我们前面讲的controller
// 二级路由
router.get("/login", (req, res, next) => {
res.send("<h1>登录页面</h1>")
})
router.get("/reg", (req, res, next) => {
res.send("<h1>注册页面</h1>")
})
// 导出路由对象
module.exports = router;
goodes.js类似user.js
。
在入口文件引入独立的模块
// app.js
const express = require("express");
// 引入二级路由文件
const userRouter = require("./routes/user")
const goodsRouter = require("./routes/goods")
const app = express();
// 一级路由 当访问/api/user时,就把这个路由交给userRouter来处理
app.use("/api/user", userRouter)
app.use("/api/goods", goodsRouter)
app.listen(3000, () => {
console.log("server is running on 3000");
})
5 会话技术
Cookie:浏览器端的会话技术。
Session:服务器端的会话技术。
5.1 什么是会话?
日常生活中:从拨通电话到挂断电话之间的一连串你问我答的过程就是一个会话。
B/S架构中:从浏览器第一次给服务器发送请求时,建立会话;直到有一方断开,会话结束。
一次会话:包含多次请求响应。
5.2 会话技术
问题:Http是一个无状态协议,同一个会话的连续两个请求相互独立,彼此并不了解。
会话技术能弥补http协议无状态带来的麻烦。
作用:用于存储浏览器与服务器在请求和响应过程中产生的数据
在一次会话中(多次请求响应), 共享数据
客户端会话技术:
cookie
服务器端会话技术:
session
5.3 cookie作用
Cookie作用:在一次会话的多次请求之间共享数据,将数据保存到
客户端(浏览器)
。
服务器可以给客户端种植一个cookie:
cookie: 小甜点 饼干 cookie本质就是存储数据的
服务器给客户端种植了一个cookie,那么这个cookie就存储在客户端。
一旦种植了,后面每一次请求,都会带上这个cookie。
服务器给客户端种植了一个cookie,cookie保存在什么地方?
答:在开发者工具中,找到application,在左侧找到cookie选项,服务器种植的cookie就存在在这个地方。
ookie的特点:
- cookie保存在客户端(浏览器), 往往是由服务器产生发送给浏览器
- cookie只能保存字符串, 格式是entry(name : value)
- cookie的大小有限制: 4k
- 一般, 同一域名下的cookie限制数量50个
使用:(需要模块:
npm i cookie-parser
)
const express = require("express")
const path = require("path")
const cookieParser = require('cookie-parser')
let app = express();
app.use(express.static(path.join(__dirname,'public')))
// 配置cookie
app.use(cookieParser())
app.get("/",(req,res)=>{
// 需要在服务端种植一个cookie,种到了浏览器的时面
// 后面,每一次请求,浏览器都会带上这个cookie
// 给客户端种植一个cookie
// res.cookie("usrename","wangcai"); // 默认情况下,会话结束,cookie就死了
// 活7天 设置cookie的生存时间
// res.cookie("username","wc",{maxAge:60000*60*24*7})
// 获取浏览器带过来的cookie
console.log("获取cookie:",req.cookies);
res.send("hello 客户端~")
})
app.listen(3000,()=>{
console.log("server is running 3000~");
})
总结:
默认cookie的生存时间:
种植:res.cookie("username","wangcai");
当浏览器关闭后,cookie就没了,这个过程,叫一次会话。默认情况下,会话结束了,cookie就没有了。
第一次,会种植一个cookie,后面再次去请求服务器时,它会把cookie携带上。
使用cookie的缺点:
1)除了第1次请求服务器,后面每一次请求服务器,都要带上cookie,浪费带宽,请求速度会慢一点。
2)因为cookie是存在浏览器端的,我们可以销毁掉,可以篡改它
3)有的用户,会在浏览器端,禁用cookie
....
设置cookie的生存周期:
res.cookie("username","wc",{maxAge:60000*60*24*7,httpOnly:true})
除了第1次请求,后面每一次请求,都会带上cookie,在服务器端,就可以
获取cookie,需要模块:
npm i cookie-parser
使用:
let cookieParser = require("cookie-parser")
app.use(cookieParser())
req.cookies // 得到客户端请求时,传递过一过来cookie
5.4 cookie记录上一次访问的时间
app.get("/", (req, res) => {
// 获取cookie 第1次获取不到,值是und
let last = req.cookies.last;
// 第1次访问服务器 需要种植一个cookie
//在浏览器种植时间一年。
res.cookie("last", new Date().toLocaleString(), { maxAge: 60000 * 60 * 24 * 356 });
if (last) {
res.send(`你上一次访问的时间是:${last}`)
} else {
// 第1次访问
res.send(`这是你第1次访问本网站`)
}
})
5.5 session的使用
session的作用:在一次会话的多次请求之间共享数据,将数据保存到服务器端。
Session基于Cookie技术实现
session是服务器端的会话技术
从浏览器第一次向服务器发起请求建立会话, 直到其中一方断开为止会话结束。
session的特点:
- session存储数据在服务器
- session存储任意类型的数据(Object)
- session存储大小和数量没有限制(在服务器内存)
- session存储相对安全
const session = require('express-session')
// 配置session
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
// session是基于cookie的
cookie: { maxAge:60000*10 }//id存在10分钟
}))
app.get("/",(req,res)=>{
// session也是存数数据的,你可以把session理解成一片存储数据的区域
// 你不需要种植cookie,内部会自动帮你种植
req.session.last = "2021-09-08"; // 当请求/时,给session区域保存一个数据
// 后面的请求,班长会带着编号来请求,会根据编号找到他对应的session
console.log("获取班长的session中对应的数据:",req.session.last);
res.send("hello session")
})
cookie和session的选择
-
cookie将数据保存在浏览器端,数据相对不安全.
建议敏感的或大量的数据不要放在cookie中,而且数据大小是有限制的
成本低,对服务器要求不高
-
session将数据保存在服务器端内存,数据相对安全.
数据的大小要比cookie中数据灵活很多
成本较高,对服务器压力较大
6 Express中间件
路由是一个特殊的中间件,如果你要定义一个正经的中间件,必须要加next。next表示放行。
6.1 next介绍
express-next方法:
1.use既可以处理没有路由地址的请求, 也可以处理有路由地址请求
2.use既可以处理get请求, 也可以处理post请求
3.在处理请求的时候是从上至下的判断的, 哪一个先满足就哪一个来处理
4.如果在处理请求的回调函数中没有调用next方法, 那么处理完之后就不会继续往下判断了
5.如果在处理请求的回调函数中调用了next方法,那么处理完之后还会继续往下判断
6.2 next使用
// 中间件的书写顺序需要特别注意
// 如果没有写路径,表示所有的请求都要经过此中间件
app.use((req,res,next)=>{
console.log("所有请求都要经过~");
// 放行
next()
})
// 不分是post还是get
// 普通的中间件
app.use("/abc",(req,res,next)=>{
console.log("我是一个中间件 111 ");
// 放行
next()
})
app.use("/abc",(req,res,next)=>{//一样的名字会继续执行 直到没有next或者路径不一样
console.log("我是一个中间件 222");
// 放行 才能走到下面的路由 注释掉不行
next()
})
/// 路由
app.get('/abc',(req, res, next)=>{
console.log('get1 /api');
next();
});
6.3 next正确使用方式
1)通过next方法, 我们可以将同一个请求的多个业务逻辑拆分到不同的方法中处理。
2)这样可以提升代码的可读性和可维护性, 以及保证代码的单一性。
6.4 express中间件
1.什么是中间件?
- 中间件的本质就是一个函数, 这个函数接收3个参数request请求对象、response响应对象、next函数
- 当请求进来,会从第一个中间件开始进行匹配。如果匹配则进入,如果不匹配,则向后依次对比匹配
2.中间件的作用?
- 将一个请求的处理过程,分发到多个环节中,目的效率高,便于维护。即每个环节专门干一件事
3.中间件的分类
3.1 应用级别中间件
绑定到app实例上的中间件
例如: app.get / app.post
3.2 路由级别中间件
绑定到router实例上的中间件
例如: router.get / router.post
3.3 错误处理中间件
与其他中间件函数的定义基本相同,
不同之处在于错误处理函数多了一个变量:err,即它有4个变量:err, req, res, next
3.4 内置中间件
express.static()、express.json()、express.urlencoded()、...
3.5 第三方中间件
cookie-parser、...
7 Express脚手架
7.1 通过express搭建项目
安装脚手架:
npm install express-generator -g
通过脚手架去创建项目:
express myapp
进入myapp中:
cd myapp
跑环境:
npm i
运行项目:
npm start (是npm run start的简写)
默认创建出来的项目,它使用的模板引擎是jade模板引擎,不需要我们不学习。
后面创建项目时,生的项目使用的模板引擎是ejs的,创建项目是指定模板引擎,如下:
命令:express -e myapp2
7.2 生成的app.js
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
// http-errors 用来处理错误的
var createError = require('http-errors');
// 打印日志
var logger = require('morgan');
// 引入二级路由模块(路由文件)
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
// 创建app应用
var app = express();
// 告诉epxress,模板放在了什么地方
app.set('views', path.join(__dirname, 'views'));
// 告诉express,使用的模板引擎是jade
app.set('view engine', 'jade');
// 使用中间件
app.use(logger('dev')); // 日志中间件
// 解析前端传的json数据
app.use(express.json());
// 解析前端传的表单数据
app.use(express.urlencoded({ extended: false }));
// 解析cookie
app.use(cookieParser());
// 托管静态资源
app.use(express.static(path.join(__dirname, 'public')));
// 配置一级路由
app.use('/', indexRouter);
app.use('/users', usersRouter);
// 配置中间件
app.use(function(req, res, next) {
// 放行
next(createError(404));
});
// 配置中间件 err
// 叫错误处理中间件
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;