Express基础

Express

基于Node.js平台,快速、开放、极简的web开发框架

使用Express

1.下载

//下载4.17.1版本
npm install express@4.17.1

2.导入包并使用

const express = require('express')
const app = express()

app.listen(80,() => {

})

路由

express中的路由是客户端请求和服务器处理函数之间的映射关系

监听请求

浏览器访问:http://127.0.0.1/getData?name=‘123’&age=20
req.query可以获取?name=‘123’&age=20访问时拼接的参数

//监听GET请求
//请求url /getData
app.get('/getData',function(req,res){
	console.log(req.query)    // { name: "'123'", age: '20' }
	res.send({name:'胡',age:20, gender:'女'}) //页面显示{name:'胡',age:20, gender:'女'}
})
//监听POST请求
app.post('/getData',function(req,res){
	res.send() // 把响应给客户端
})

使用:动态匹配, req.params获取动态参数
浏览器访问:http://127.0.0.1/getData/2

//动态匹配
app.get('/getData/:id',function(req,res){
	console.log(req.params)    // 2
	res.send({name:'胡',age:20, gender:'女'}) //页面显示{name:'胡',age:20, gender:'女'}
})

浏览器访问:http://127.0.0.1/getData/2/hu

app.get('/getData/:id/:name',function(req,res){
	console.log(req.params)    // { id: '2', name: 'hu' }
	res.send({name:'胡',age:20, gender:'女'}) //页面显示{name:'胡',age:20, gender:'女'}
})

路由匹配规则:

  1. 路由先后顺序进行匹配
  2. 请求类型和请求地址同时匹配成功 才会调用函数
托管静态资源

使用express.static()
存放静态资源的目录名不会出现在url中
托管多个静态资源目录时,根据目录的添加顺序查找所需的文件

app.use(express.static('public'))
app.use(express.static('./public2'))
// public 目录下的图片、文件资源都可以访问

// 访问public/images/bg.jpg  http://127.0.0.1/images/bg.jpg
// 访问public/index.html http://127.0.0.1/index.html
路由模块

在项目中我们通常需要定义的接口往往很多,所以需要把模块化路由。

  1. 创建路由模块对应的.js文件
  2. 调用express.Router()函数创建路由对象
  3. 向路由对象上挂载具体的路由
  4. 使用module.exports向外共享路由
  5. app.use函数注册路由
//创建route.js文件
const express = require('express')

const router = express.Router()

router.get('/user/list',(req, res) => {
    res.send('userlist')
})
router.post('/user/add',(req, res) => {
    res.send('post')
})

module.exports = router
//启动文件中
const router = require('./route')
app.use(router)

Express中间件

中间件有输入输出。
express 可以连续调用多个中间件,从而对这次请求 请求预处理。

中间件的作用

多个中间件之间,共享同一份req和res
我们可以在上游的中间件中,统一为req和res对象添加自定义的属性或方法供下游的中间件或路由使用。

中间件的使用
const express = require('express')

const app = express()
//中间件
app.get('/',function(req,res,next){
	req.time = Date.now
    next()
})
//可以访问到req.time
app.get('/use',function(res,req){
   console.log(req.time)
})

包含了next参数回调函数就是中间件,未包含是路由处理函数
next函数的作用:

  1. next函数是实现多个中间件连续调用的关键
  2. 它把流关系转交给下一个中间件或路由
全局中间件

方式一:

const mw = function (req,res, next) {
    next()
}
app.use(mw)

方式二:

app.use(function (req,res, next) {
    next()
})
局部中间件

不使用app.use()就是局部中间件
// mw中件件参数

const mw = function (req,res, next) {
    next()
}
app.get('/',mw,function(req,res){
    // 中间件只在当前中作用
})

定义多个中间件 以下两种等价

app.get('/',mw1,mv2,function(req,res){
    // 中间件只在当前中作用
})

app.get('/',[mw1,mv2],function(req,res){
    // 中间件只在当前中作用
})

注意: 一定要在路由之前注册中间件,把中间件件放到路由后面 路由就无法使用

中间件执行规则

连续定义多个中间件,会安照定义的先后顺序依次调用。

中间件分类

官方把常见的中间件用法,分成了5大类分别是:

1.应用级别的中间件

绑定到app实例上的中间件

app.use()
app.get()
app.post()
2.路由别的中间件

绑定到express.Router()实例上的中间件

3.错误级别的中间件

专门用来捕获整个项目中发生的异常错误,防止程序崩溃。必须有四个参数(err,req,res,next)
错误中间件必须注册在路由之后

4.Express内置的中间件

三个常用的内置中间件:

  1. express.static 托管静态资源文件
  2. express.json json格式的请求体数据(有兼容性,仅在4.16.0+版本中可用)
    json格式的请求体数据(有兼容性,仅在4.16.0+版本中可用)
    3.express.urlencoded 解析URL-encode格式的请求体数据(有兼容性,仅在4.16.0+版本中可用)
    不配置解析中间件为undefined
//在路由之前配置
app.use(express.static('public'))
app.use(express.json())
app.use(express.urlencoded({extended:false}))
5.第三方的中间件

使用第三方中间件body-parser:res.body 获取JSON 格式表单数据和url-encoded格式的数据

//1.下载
npm install body-parser
//2.导入包
const parser = require('body-parser')
//3.app.use
app.use(parser.urlencoded({extended:false}))

nodemon

使用插件,避免每次修改内容后,都需要收到启动服务器

//下载
npm install -g nodemon
//启动服务
dnoemon app.js //app.js 启动文件

Express解决接口跨域问题

协议、域名 、端口其中一个不同就会存在跨域

使用CORS第三方中间件
  1. 安装
npm install cors
  1. 使用
const cros = require('cors')
  1. 在路由之前调用
app.use(cors())
CORS跨域资源共享

CORS跨域资源共享由一系列HTTP响应头组成,这些HTTP响应头决定。
浏览器是阻止 前端js代码跨域获取资源

CORS在浏览器中有兼容性,只支持XMLHttpRequest level2浏览器,才能正常访问开启CROS的服务器接口

CORS响应头部有三个响应头:
  1. Access-Control-Allow-Origin
    Access-Control-Allow-Origin:<origin> | *origin参数允许访问资源的外域URL
// 只允许来自https://cn.vuejs.org/的请求
res.setHeader('Access-Control-Allow-Origin','https://cn.vuejs.org/')
//允许来自任何域的请求
res.setHeader('Access-Control-Allow-Origin','*')
  1. Access-Control-Allow-Headers
    默认情况下,CORS仅支持客户端发送如下的9个请求头
    在这里插入图片描述

如果客户端向服务器发送了额外的请求头信息,则需要通过Access-Control-Allow-Headers对额外的请求头进行申明,否则这次请求失败

 // 允许客户端额外向服务器发送请求头 Content-Type X-Custom-Header
res.setHeader('Access-Control-Allow-Headers','Content-Type', 'X-Custom-Header')
//多个请求头之间用英文逗号进行分隔  

3.Access-Control-Allow-Methods
默认情况下COES仅支持客户端发起 GET、POST、HEAD请求,PUT 、DELETE 需要 指明实际请求所允许使用的HTTP方法

//允许请求方式:GET POST HEADPUT DELETE
res.setHeader('Access-Control-Allow-Methods', 'GET', 'POST', 'HEADPUT', 'DELETE',)
//允许所有请求方式
res..setHeader('Access-Control-Allow-Methods','*')
预检请求

普通请求 只发生一次请求 预检请求会发生两次
什么情况下会预检请求?

  1. GET、POST、HEAD之外的的请求类型
  2. 请求头中包含自定义头部字段
  3. 向服务器发送了 application/json 格式的数据
    预检请求会先发送 OPTION请求进行预检,以获知服务器是否允许该实际请求 ,成功后才会发送真正的请求并携带真实数据
JSONP解决跨域

浏览器通过<script>标签的src属性,请求服务器上的数据同时服务器返回一个函数的调用
只支持GET
为了防止冲突 必须在配置CORS中间件之前申明JSONP的接口
字符串拼接出一个函数调用的字符串 在<script>标签执行解析

app.get('/api/jsonp',(req,res) => {
    const funcName = req.query.callback
    const data = {}
    const scriptStr = `${funcName}(){${JSON.stringify(data)}}`
    res.send(scriptStr)
})

Express中使用MySQL

MySQL传统性数据库,MySQL是用来组织、存储和管理数据的仓库

MySQL安装

下载mysql地址:https://dev.mysql.com/downloads/mysql/
下载后进行安装,会安装如下两个:
MySQL Server 专门用来提供数据存储和服务的软件
MySQL Workbench 可视化的MySQL管理工具

在项目中操作MySQL

  1. 安装操作MySQL数据库的第三方模块
npm install mysql
  1. 通过mysql模块连接到MySQL 数据库
const mysql = require('mysql')

const db = mysql.createPool({
    host: '127.0.0.1', // 数据库的IP地址
    user: 'root', // 登录数据库的账号
    password: '123456', // 数据库的密码
    database: 'my_database', // 指定操作哪个数据库
})
  1. 通过mysql模块 执行SQL语句
    先测试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,results) => {
    if (err) return console.log(err.message)
    console.log(results)
})
插入数据
const user = {username: 'hu1',passsowrd:'node123'}
const sqlStr = 'insert into users (username,passsowrd) values (?,?)' 
db.query(sqlStr ,[user.username,user.passsowrd] ,(err,results) => {
    if (err) return console.log(err.message)
    if (results.affectedRows === 1) { 
        console.log('插入数据成功')
    }
    console.log(results)
})

便捷插入

const user = {username: 'hu2',passsowrd:'node456'}
const sqlStr = 'insert into users set ?' 
// 数据对象的每一个属性和数据表字段一一对应
// 直接将数据对象当做占位符
db.query(sqlStr, user ,(err,results) => {
    if (err) return console.log(err.message)
    if (results.affectedRows === 1) { 
        console.log('插入数据成功')
    }
    console.log(results)
})
更新数据
const user = {id:6,username: 'huq2',passsowrd:'node789'}
const sqlStr = 'update users set username=?,passsowrd=? where id=?' 
db.query(sqlStr, [user.username,user.passsowrd,user.id] ,(err,results) => {
    if (err) return console.log(err.message)
    if (results.affectedRows === 1) { 
        console.log('更新数据成功')
    }
    console.log(results)
})

便捷更新数据

const user = {id:6,username: 'huq2',passsowrd:'node789'}
const sqlStr = 'update users set ? where id=?' 

db.query(sqlStr, [user,user.id] ,(err,results) => {
    if (err) return console.log(err.message)
    if (results.affectedRows === 1) { 
        console.log('更新数据成功')
    }
    console.log(results)
})
删除数据

id唯一标识

const sqlStr = 'delete from users where id=?' 

db.query(sqlStr, 6 ,(err,results) => {
    if (err) return console.log(err.message)
    if (results.affectedRows === 1) { 
        console.log('删除数据成功')
    }
    console.log(results)
})

直接删除delete不能找回数据,所以在项目中最好使用标记删除,定义一个 status删除状态,设置为1,就代表数据已删除

const sqlStr = 'update users set status=1 where id=?' 
db.query(sqlStr, 6 ,(err,results) => {
    if (err) return console.log(err.message)
    if (results.affectedRows === 1) { 
        console.log('删除数据成功')
    }
    console.log(results)
})

前后端的身份认证

Web开发模式主流:

第一种:基于服务器渲染的传统Web开发模式,服务发送给客户端的HTML页面,是在服务器通过字符串的拼接,动态生产的,不需要Ajax额外请求页面数据
优点:

  1. 耗时少, 浏览器只需要直接渲染页面,尤其是移动端更省电
  2. 有利于SEO
    缺点:占用服务器端资源 会造成压力
    不利于前后端分离,开发效率低
    第二种:基于前后端分离的新型web开发模式,后端只负责提供API接口,前端使用Ajax调用接口的开发模式
    优点:开发体验好,用户体验好,减轻了服务器的渲染压力
    项目具体使用哪种开发模式需要通过项目需求来选择合适的方式
    也可以结合使用,比如:首屏服务器渲染+其他页面前后端分离
session的工作原理

通过一定手段,完成对用户身份的确认
目的:确认当前申称为某种用户,确实是所声称的某种用户
前后端分离推荐使用Session认证机制、JWT认证机制
1.http协议的无状态性
是指客户端每次HTTP请求都是独立的,连续多个请求之间没有直接关系,服务器不会主动保留每次HTTP请求
2.如何突破HTTP无状态机制
使用Cookie。
Cookie是存储在用户浏览器的一段不超过4kb的字符串,它由一个名称、一个值和其他几个用于控制Cookie有效性、安全性、使用范围的可选属性组成
不同域名下的Cookie各自独立,每当客户端发起请求时
会自定把当前域名下所有未过期的cookie一同发送到服务器。
Cookie特征:自动发送、域名独立、过期时限、4kb限制

客户端第一次请求的时候,服务器通过响应头的形式,向客户端发送一个身份认证Cookie,客户端会自动将Cookie保存到浏览器。随后,当客户端浏览器每次请求服务器的时候,浏览器会将身份认证相关的cookie,通过请求头的形式发送给服务器,服务器级可验明客户端的身份
在这里插入图片描述

Cookie不具有安全性
由于cookie是存储在浏览器中的,而且浏览器也提供了读写Cookie的API,因此Cookie很容易被伪造
不建议服务器将重要的隐私数据,通过cookie形式发送给浏览器
提高身份认证的安全性,使用Session认证机制

在Express中使用Session认证

npm install express-session
app.use(session({
    secret:'HUQIN', //任意字符串
    resave: false, //固定写法
    saveUninitialized:true //固定写法
}))

app.get('/login',(req,res) => {
    // 配置session后可以使用req.session
    if(req.query.password!=='123') {
    }
    req.session.user = req.query
    req.session.islogin = true
    res.send('登录成功')
})

app.get('/userData',(req,res) => {
    if(!req.session.islogin){
        return res.send('获取数据失败')
    }
    res.send('成功')
})

JWT认证机制

Session认证的局限性:Session认证机制需要配合Cookie才能实现,由于Cookie默认不支持跨域访问,所以,当涉及到前端跨域请求后端接口的时候,需要做很多额外配置才能实现Session认证。
JWT认证机制最流行跨域认证解决方案
通常由三部分组成:
Header(头部)
Payload(有效载荷) 真正的用户信息
Signature(签名)
其它两个是安全性相关部分,只是为了保证Token的安全性使用. 进行分隔

Header.Payload.Siginature

客户端通常会把JWT存储在localSoragesessionStorage中,每次请求都有带上JW字符串 从而进行身份认证
在这里插入图片描述

推荐把jwt放在请求头中的Authorization字段后
Authorization:Bearer
使用JWT需要下载两个模

npm install jsonwebtoken express-jwt

jsonwebtoken 生产jwt字符串

express-jwt 将jwt字符串解析还原成JSON对象

const jwt = require('express-jwt')
const expressJWT = require('express-jwt')
const secreKey = 'xiaohuzi' //加密的key 可以是任意字符串
// 只有配置成功 就可以使用req.user
app.use(expressJWT({secret: secreKey}).unless({path:[/^\/api\//]}))// 使用正则配置api开头不需要访问权限
app.get('/login',(req,res) => {
    //userInfo 模拟获取到的值
    const userInfo = {username:'xiaohuzi'}
    const tokenStr = jwt.sigin({username:userInfo.username},secreKey,{expiresIn:'30s'})
    res.send({
        status:200,
        token:tokenStr
    })
    res.send('登录成功')
})
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值