Express 是基于 Node.js 平台, 快速,开放,极简的 Web 开发框架
安装
在项目所处的根目录中运行:
npm i express@4.17.1
创建基本的 Web 服务器
//导入 express
const express = require('express')
// 创建 web 服务器
const app = express()
//
app.get('/user/:id', (res, req) => {
res.send() //向客户端响应文本或字符串
req.query() //默认是个空对象;可以获取到客户端发送过来的查询参数例 ?name=zs&age=20
req.params //默认空对象,可以访问到URL中,通过: 匹配到的动态参数[:id]
// :必须写 id可以任意修改,它是参数的名字
//还可以写多个 'user/:id/:name/:age'
})
// 调用 app.listen(端口号, 启动成功后的回调函数) ,启动服务器
app.listen(80,() => {
console.log('express server running at http://127.0.0.1')
})
监听 GET 请求
app.get('URL', function(res, req) {
})
// res : 请求对象(包含与请求相关的属性和方法)
// req : 响应对象(包含与响应相关的属性和方法)
监听 POST 请求
app.post('URL', function(res, req) {
})
通过该函数我们可以非常方便的创建一个静态资源服务器,实现某个目录中的文件对外开放访问;存放静态文件的目录名不会出现在 url 中
app.use(express.static('public'))
托管多个静态资源
即多次调用 express.static() 函数
访问静态资源文件时, express.static() 函数会根据目录的添加顺序查找所需的文件
ALT+ shang
挂载路径前缀
app.use('/abc',express.static('./abc'))
路径前 挂载 前缀
监听项目文件的变动,当代码被修改后, nodemon 会自动帮我们重启项目
安装
npm install -g nodemon
使用
将 node 改为 nodemon
express中的路由就是映射关系: 客户端的请求与服务器处理函数之间的映射关系
分为三部分: 请求的类型(METHOD), 请求的URL 地址(PATH), 处理函数(HANDLER):
app.METHOD(PATH, HANDLER)
路由的匹配
//导入 express
const express = require('express')
//创建路由对象
const router = express.Router()
//挂载具体的路由
router.get('/', (req, res) => {
})
router.post('/',(req, res) => {
})
//向外导出路由对象
module.exports = router
const express = require('express')
const app = express()
const router = require('./url')
//注册路由模块
app.use(router)
app.use() //函数作用,注册全局中间件
app.use('/abc',router)
格式
function(req, res, next)
next 函数是实现多个中间件连续调用的关键, 他表示把流转关系转交给下一个中间件或路由.
const express = require('express')
const app = express()
//定义一个最简单的中间件函数
const mw = function(req, res, next) {
//把流转关系转交给下一个中间件或路由
next()
}
app.listen(80,() => {
})
全局生效的中间件
客户端发起的任何请求, 到达服务端后,都会触发的中间件,叫做全局生效的中间件
app.use(mw)
简化形式全局中间件
app.use((req, res, next) => {
next()
})
作用:
多个中间件之间,共享同一份 req 和 res.基于这样的特性,我们可以在上游的中间件中, 统一为 req 和 res 对象添加自定义属性或方法,供下游的中间件或路由进行使用
局部生效的中间件
不使用 app.use() 的中间件
const express = require('express')
const app = express()
const mw1 = (req ,res ,next) => {
next()
}
app.get('/',mw1,(req, res) => {
//mw1只在此函数中生效
//若有多个局部中间件 添加到mw1后面,用逗号(,)隔开
})
app.post('/',(req, res) => {
})
app.listen(80, () => {
})
中间件的使用注意事项
路由级别的中间件
错误级别的中间件
//定义错误级别的中间件, 捕获整个项目的异常错误, 从而防止程序的崩溃
app.use(err, req, res, next) => {
res.send('Error:' + err.message)
}
//错误级别中间件要放在所有路由之后
req.body 属性,接受客户端发送过来的请求体数据;
如果不配置解析表单数据的中间体,则 req.body 默认等于 undefined
app.use(express.json()) //内置中间件
app.use(express.urlencoded({extended:false}))
在路由中 使用 req.body
pk: 主键, 唯一标识符
NN: 值不允许为空
UQ: 值唯一
AI: 值自动增长
Default/Expression : 默认值
SQL 是结构化查询语言, 专门用来访问和处理数据库的编程语言.能够让我们以编辑的形式, 操作数据库里面的数据.
--
注释
从 FROM 指定的[表中],查询出[所有的]数据, * 表示[所有列]
select * from 表名称
从 FROM 指定的[表中], 查询出指定列名称的数据
select 列名称 from 表名称
向数据表中插入新的数据行
insert into 表名称(列1,列2...) values (值1, 值2,...)
修改表中的数据
update 表名称 set 列名称 = 新值 where 列名称 = 某值
多个列更改,用逗号隔开
删除表中的行
delete form 表名称 where id=
关键字对大小写不敏感
where 子句用于限定选择的标准 .
<>和!=都表示不等号
and 必须同时满足多个条件
or 任一条件满足即可
order by 根据指定的列对结果集进行排序,默认按升序(ASC)排序(DESC关键字,可以降序排序)
select * from users order by id
默认升序
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tM1nzSVY-1647130047397)(C:\Users\Lenovo\Desktop\typora\img\orderby.png)]
select * from users order by id desc
降序
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e8nLNXfo-1647130047399)(C:\Users\Lenovo\Desktop\typora\img\orderbydesc.png)]
多个排序规则时,用逗号分隔
count(*)函数用于返回查询结果的总数据条数
select count(*) from 表名称
给列起别名
select username as uname, password as upwd from users
npm install mysql
建立与 mysql 数据库的连接
const db = mysql.createPool({
host: '127.0.0.1', //数据库的 IP 地址
user: 'root', //登录数据库的账号
password: 'admin123', //登录数据库的密码
database: 'my_db_01' //指定要操作那个数据库
})
测试 MySQL 模块是否正常工作
db.query('select 1',(err, results) => {
if(err) return console.log(err.message)
console.log(results)
})
查询 users 表中所有数据
const sqlStr = 'select * from users'
db.query(sqlStr, (err, result) => {
if(err) return console.log(err.message)
//如果使用 select 查询语句,执行的结果为 数组
console.log(result)
})
插入数据
//要插入到 users 表中的数据对象
const user = { username: 'Spider-Man', password: 'pcc121'}
//待执行的 SQL 语句, 其中英文的 ? 表示占位符
const sqlStr = 'insert into users(username, password) value(?, ?)'
//使用数组的形式依次为 ? 占位符指定具体的值
db.query(sqlStr, [user.username, user.password], (err, results) => {
if(err) return console.log(err.message)
//如果执行 insert into 插入语句, 则 results 是一个对象
if(results.affectedRows === 1) { //判断是否插入成功
console.log('插入数据成功')
}
})
插入数据的便捷方式
//要插入到 users 表中的数据对象
const user = { username: 'Spider-Man', password: 'pcc121'}
//待执行的 SQL 语句, 其中英文的 ? 表示占位符
const sqlStr = 'insert into users SET ?'
//直接将数据对象作为占位符
db.query(sqlStr, user, (err, results) => {
if(err) return console.log(err.message)
//如果执行 insert into 插入语句, 则 results 是一个对象
if(results.affectedRows === 1) { //判断是否插入成功
console.log('插入数据成功')
}
})
更新数据
const user = {id: 6, username: 'aaa', password: '000'}
const sqlStr = 'update users set username=?, password=? where id=?'
db.query(sqlStr, [user.username, user.password, user.id], (err, results) => {
if(err) return console.log(err.message)
//如果执行 insert into 插入语句, 则 results 是一个对象
if(results.affectedRows === 1) { //判断是否插入成功
console.log('更新成功')
}
})
更新数据的便捷方式
// 要更新的数据对象
const user = { id = 7, username: 'aaaa', password: '0000'}
// 要执行的 sql 语句
const sqlStr = 'update users set ? where id=?'
//调用 db.query() 执行sql语句,同时使用数组依次为占位符指定具体的值
db.query(sqlStr, [user,user.id], (err, results) => {
if(err) return console.log(err.message)
if(results.affectedRows === 1) {
console.log('更新数据成功')
}
})
删除数据
const delete = 'delete from users where id=?'
db.query(sqlStr, 5, (err, results) => {
if(err) return console.log(err.message)
if(results.affectedRows === 1) {
console.log('删除数据成功')
}
})
标记删除
const sqlStr = 'update users set status=? where id=?'
db.query(sqlStr, [1, 6], (err, results) => {
if(err) return console.log(err.message)
if(results.affectedRows === 1) {
console.log('删除数据成功')
}
})
HTTP 协议的无状态性指的是客户端的每次 HTTP 请求都是独立的, 连续多个请求之间没有直接的关系, 服务器不会注定保留每次 HTTO 请求的状态.
如何突破 HTTP 无状态的限制?
Cookie 是存储在用户浏览器中的一段不超过 4kb 的字符串, 它由一个名称, 一个值和其他几个用于控制 Cookie 有效期,安全性,使用范围的 可选属性组成.
不同域名下的 Cookie 各自独立, 每当客户端发起请求时, 会自动把当前域名下所有未过期的 Cookie 一同发送到服务器.
Cookie 的几大特性: 1. 自动发送 2. 域名独立 3. 过期时限 4. 4KB 限制
在身份认证中的作用: 客户端第一次请求服务器的时候, 服务器通过响应头的形式, 向客户端发送一个身份认证 Cookie , 客户端会自动将 Cookie 保存在浏览器中.
随后, 当客户端浏览器每次请求服务器的时候, 浏览器会自动将身份认证相关的 cookie ,通过请求头的形式发送给服务器 服务器即可查明 客户端的身份
Cookie 不具有安全性, 千万不要使用 Cookie 存储重要且隐私的数据!
提高身份认证的安全性
session 的工作原理
安装 express-session
npm install express-session
配置
const express = require('express')
const session = require('express-session')
const app = express()
app.use(
session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true
}))
存储信息
req.session.user = req.body
req.sesion.islogin = true
清空 session
req.session.destroy()
清空服务器保存的 session 信息
JWT组成的三部分:
Header(头部).Payload(有效荷载).Signature(签名)
三者间用 . 隔开
Payload 部分才是用户的真实信息, 它是用户信息经过加密之后生成的字符串
Header 和 Signature 是安全性相关的部分 , 只是为了保证 Token 的安全性
使用方式
Authorization: Bearer <token>
安装 JWT 相关的包
npm install jsonwebtoken express-jwt
jsonwebtoken 用于生成 JWT 字符串
express-jwt 用于将JWT 字符串解析还原成 JSON 对象
定义 secret 密钥
为了保证 JWT 字符串的安全性, 我们专门定义了一个用于 加密 和 解密 的 sercet 密钥:
const secreKey = 'itheima No1 ^_^'
在登陆后生成 JWT 字符串
参数一:用户的信息对象
参数二: 加密的密钥
参数三: 配置对象, 可以配置当前 token 字符串
sign({username: userinfo.username}, secretKey, { expiresIn: '100s'})
将 JWT 字符串还原为 JSON 对象
req.user()获取用户信息