原生的 Http
Node之 Express 框架
npm i express -g -D
Express
Express 托管静态资源
const express = require('express');
const app = express();
const PORT = 3000;
//托管静态资源 express.static('xxx') xxx文件夹的作为静态资源
app.use(express.static('public'))
// 比如 根目录下有个public文件夹,里面有个images、css、js 文件夹
//这样 就可以访问 http://域名(IP)/images/1.png
//这样 就可以访问 http://域名(IP)/css/style.css
//这样 就可以访问 http://域名(IP)/js/1.js
// 托管多个静态资源目录
//托管静态资源 express.static('xxx') xxx文件夹的作为静态资源
app.use(express.static('public'))
app.use(express.static('custpublic'))
//多个静态资源目录
// 访问静态资源文件时,express.static() 函数会根据目录的 添加顺序 查找所需文件
//托管静态资源 挂载路径前缀 通常前缀跟目录名称一样 下面的xxx -》public
app.use(”xxx“,express.static('public'))
//这样 访问静态资源 需要添加 xxx 作为前缀了
//这样 就可以访问 http://域名(IP)/xxx/images/1.png
//这样 就可以访问 http://域名(IP)/xxx/css/style.css
//这样 就可以访问 http://域名(IP)/xxx/js/1.js
// 基础路由
app.get('/', (req, res) => {
res.send('欢迎来到Express服务器!');
});
// 启动服务器
app.listen(PORT, () => {
console.log(`服务器运行在 http://localhost:${PORT}`);
});
Express》》app.use() 函数 、中间件
# app.use() 方法用于指定中间件函数,其基本形式如下所示:
app.use([path], middleware)
其中,[path] 参数是可选的,代表中间件函数所处理的路径,默认为“/”。middleware 参数是中间件函数,可以是一个函数或者是一个由若干个函数组成的数组。如果 middleware 参数是数组,则每个函数都会按照在数组中的顺序依次被执行。
const express = require('express');
const app = express();
// 身份验证中间件
function authenticate(req, res, next) {
if (req.session.user) {
next(); // 用户已登录,继续处理请求
} else {
res.redirect('/login'); // 用户未登录,重定向到登录页面
}
}
// 将身份验证中间件绑定到所有路由上
app.use(authenticate);
// 处理 GET /home 请求的路由处理器
app.get('/home', function (req, res) {
res.send('欢迎访问主页!');
});
// 处理 GET /profile 请求的路由处理器
app.get('/profile', function (req, res) {
res.send('欢迎访问个人资料页面!');
});
// 启动服务器并监听端口号3000
app.listen(3000);
1.托管静态资源
# 将 public 目录中的所有静态文件映射到根目录的 /public 路径下
app.use('/public', express.static(__dirname + '/public'));
2.处理Json
app.use(express.json());
# 如果要在处理 JSON 时,限制请求体的大小为 10MB,则可以使用下面的代码:
app.use(express.json({ limit: '10mb' }));
3. 处理 URL 编码数据
app.use(express.urlencoded({ extended: false }));
4.处理错误
# 在 Express.js 中,可以使用 app.use() 方法为应用程序添加错误处理中间件。当我们的应用程序发生了错误后,错误处理中间件将会 自动捕获此错误,并采取适当的措施进行处理。
app.use(function (err, req, res, next) {
console.error(err.stack)
res.status(500).send('Something broke!')
})
》》中间件的作用 路由本质上是一种特殊类型的中间件
多个中间件(含路由)之间,共享 同一份 req、res, 基于这个特性,我们可以在上游的中间件中,统一为 req 或 res 对象添加 自定义 的属性或方法,供下游 的中间件或路由 使用
// 为了方便 演示,把中间件、路由 放在同一个 js 文件下了。 实际开发 会抽离出去。
const express = require('express')
const app = express()
app.use((req,res,next)=>{
req.x="32"
})
app.use((req,res,next)=>{
// req 也上面的 x 属性
req.y="123"
})
app.get('/home',(req,res)=>{
//此时的req 就有上面自定义的 x、y的属性
})
app.listen(3000),()=>{
});
》》全局中间件 、局部中间件
1…用 app.use() 就是 全局中间件
2。不用 app.use() 就是 局部中间件
const express = require('express')
const app = express()
//定义一个中间件
const mv = (req,res,next)=>{
req.x="32"
})
//此时mv 就是 局部中间件
// 可以在路由中 定义多个局部中间件
//app.get('/home',mv1,mv2,(req,res)=>{})
//app.get('/home',[mv1,mv2],(req,res)=>{})
app.get('/home',mv,(req,res)=>{
})
app.get('/about',(req,res)=>{
})
app.listen(3000),()=>{
});
中间件的注意事项 和 分类
中间件使用注意事项
- 一定要在路由之前注册中间件——》因nodejs 中间件(含路由)是自上而下的顺序执行的
- 客户端发来的请求,可以连续调用多个中间件 (鉴权、授权、日志等)
- 执行完中间件的业务代码后, 切记 不要忘记 使用 next() 函数。
- 为了防止代码逻辑混乱,调用 next() 函数后不要再写额外的代码
- 连续调用多个中间件,共享 req 和 res 对象
》》中间件的分类
// 1. 应用级别
// 通过app.use()、app.get()、app.post() 绑定到 app实例上的 中间件,就叫应用级别中间件
app.use((req,res,next)=>{ ... next()}) 应用级别中间件(全局中间件)
app.get('/' , mv1,(req,res)=>{ ... }) 应用级别中间件(局部中间件) mv1 是中间件函数
// 2. 路由级别
// 绑定到路由实例上的中间件,叫 路由级别中间件。
// 路由文件
const express = require('express')
const router = express.Router()
router.use((req,res,next)=>{
...
next()
})
router.get('/xx',(req,res)=>{
res.send('路由模块 get')
})
router.post('/xx',(req,res)=>{
res.send('路由模块 post')
})
// 暴露
module.exports=router
// 3. 错误级别 注册要在所有路由的后面
// 专门用来捕获 整个项目 中的异常错误的,防止项目崩溃的
// 错误中间 必须 必须 必须 有四个参数, 顺序不能改变 (err,req,res,next)
app.get('/',(req,res)=>{
//为了方便演示 人为抛出一个异常
throw new Error('xxxxxx')
res.send('nnnnnn') //因为上面异常了,此处不会执行了
})
。。。。
//错误中间件 用于捕获项目的错误、异常
app.use((err,req,res,next)=>{
console.log(err.message)
res.send(err.message)
})
// 4. Express内置
1 express.static 托管静态资源(html文件、图片、css)无兼容性
2 express.json 解析Json格式的 请求体数据 (有兼容性 Express版本 4.16.0+可用)
3 express.urlencoded 解析URL-encoded 格式的 请求体数据 (有兼容性 Express版本 4.16.0+可用)
// 配置解析 application/json 格式的请求数据
app.use(express.json())
app.post('/user',(req,res)=>{
// 在服务器,可用使用 req.body 这个属性 来接受客户端发送过来的请求数据 (JSON 格式、 url-encoded格式)
// 默认情况下,如果不配置解析表单(app.use(express.json()))数据的中间件,则 req.body 默认等于 undefined
console.log(req.body)
res.send('xxx')
})
// 配置解析 application/x-www-form-urlencoded 格式数据
app.use(express.urlencoded({ extended : false }))
app.post('/user',(req,res)=>{
// 在服务器,可用使用 req.body 这个属性 来接受客户端发送过来的请求数据 (JSON 格式、 url-encoded格式)
// 默认情况下,如果不配置解析表单(app.use(express.urlencoded({ extended : false })))数据的中间件,则 req.body 默认等于 undefined
console.log(req.body)
res.send('xxx')
})
// 5. 第三方中间件
// 非Express官方内置的 ,都是第三方中间件
// 在 Express版本 4.16.0之前的版本 服务器解析 JSON、url-encoded 格式数据 需要引入 第三方中间件 即 body-parser
// Express版本 4.16.0之后的版本 内置的 express.urlencoded 、express.json 中间件,就是基于 body-parser 这个第三方中间件进一步封装的
// 使用步骤 如下
1 安装 npm i body-parser
2 使用 require 引入中间件
3 调用 app.use() 注册并使用中间件
const bodyParser = require('body-parser')
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({extended:false}))
Express 》》自定义中间件
const express = require('express');
const qs = require('querystring')
const app = express();
const PORT = 9090;
//除错误中间件要放在路由后面,其它的中间件一律要放在路由之前
// 自定义 应用级别(全局中间件)
//定义变量 ,用来存储 客户端发送过来的请求数据
let req_data=''
app.use((req,res,next)=>{
//在中间件中,要监听 req 对象的 data 事件,来获取客户端发送到服务器的数据
// 如果数据量比较大,无法一次性发送完毕,则客户端会数据切割后,分批发送到服务器。
// 所以data事件可能会会触发多次,每次触发data事件时, 获取到数据只是完整数据的一部分,
// 需要手动对接收到的数据进行拼接
req.on('data',(chunk)=>{
// 拼接请求体数据,隐式转换为字符串
req_data+=chunk
})
// 监听 req 对象的 end 事件 (请求体发送完毕后自动触发)
req.on('end',()=>{
// 打印完整的请求体数据
console.log(req_data)
// 把字符串格式的请求体数据,解析成对象格式 JSON
// Node.js 内置一个 querystring模块,专门用来处理查询字符串。
// 通过这个模块提供的parse()函数,可以把字符串解析成对象格式
const body = qs.parse(req_data)
//因为上游中间件、下游中间件、路由之间 共享同一份 req 、res
// 所以可以把解析出来的请求数据 挂载为 req 的自定义属性
req.body= body
console.log(body)
})
next()
})
// 处理 GET /home 请求的路由处理器
app.get('/home', function (req, res) {
res.send('欢迎访问主页!');
});
// 处理 GET /profile 请求的路由处理器
app.get('/profile', function (req, res) {
res.send('欢迎访问个人资料页面!');
});
// 启动服务器
app.listen(PORT, () => {
console.log(`服务器运行在 http://localhost:${PORT}`);
});
》》上面 自定义中间件和 app混合在一起了, 下面 抽离出去 封装中 独立的模块
// 文件 custom_mw.js
const qs = require('querystring')
//除错误中间件要放在路由后面,其它的中间件一律要放在路由之前
// 自定义 应用级别(全局中间件)
//定义变量 ,用来存储 客户端发送过来的请求数据
let req_data=''
const mv =(req,res,next)=>{
//在中间件中,要监听 req 对象的 data 事件,来获取客户端发送到服务器的数据
// 如果数据量比较大,无法一次性发送完毕,则客户端会数据切割后,分批发送到服务器。
// 所以data事件可能会会触发多次,每次触发data事件时, 获取到数据只是完整数据的一部分,
// 需要手动对接收到的数据进行拼接
req.on('data',(chunk)=>{
// 拼接请求体数据,隐式转换为字符串
req_data+=chunk
})
// 监听 req 对象的 end 事件 (请求体发送完毕后自动触发)
req.on('end',()=>{
// 打印完整的请求体数据
console.log(req_data)
// 把字符串格式的请求体数据,解析成对象格式 JSON
// Node.js 内置一个 querystring模块,专门用来处理查询字符串。
// 通过这个模块提供的parse()函数,可以把字符串解析成对象格式
const body = qs.parse(req_data)
//因为上游中间件、下游中间件、路由之间 共享同一份 req 、res
// 所以可以把解析出来的请求数据 挂载为 req 的自定义属性
req.body= body
console.log(body)
})
next()
}
module.exports = mv
const express = require('express');
const cust_mv = require('./custom_mw')
const app = express();
const PORT = 9090;
// 应用自定义中间件
app.use(cust_mv)
// 处理 GET /home 请求的路由处理器
app.get('/home', function (req, res) {
res.send('欢迎访问主页!');
});
// 处理 GET /profile 请求的路由处理器
app.get('/profile', function (req, res) {
res.send('欢迎访问个人资料页面!');
});
// 启动服务器
app.listen(PORT, () => {
console.log(`服务器运行在 http://localhost:${PORT}`);
});
Express 路由模块
# 为了方便对路由进行模块化管理,Express 不推荐将路由 直接 挂载 在 app上,而是推荐将路由抽离为单独的模块
# 将路由抽离为单独的模块 步骤如下
1. 创建对应的 路由模块 js
2. 调用express.Router() 函数创建路由实例(即路由对象)
3. 向路由对象上,挂载具体的路由
4. 使用module.exports 向外暴露
# 路由模块创建完毕,如何使用 步骤如下
1. 通过require 引入
2. 使用app.use() 函数注册路由模块
// 导入express 框架
const express = require('express')
// 创建路由实例
const router = express.Router()
//往路由实例上挂载 具体路由
router.get('/xx',(req,res)=>{
res.send('路由模块 get')
})
router.post('/xx',(req,res)=>{
res.send('路由模块 post')
})
// 暴露
module.exports=router
const express = require('express');
const router = require('./routerx')
const app = express();
const PORT = 3000;
//注册路由模块
// app.use() 函数 作用 就是 注册 全局中间件(静态资源、路由等)
app.use(router)
//如果要为路由模块前进前缀
app.use('/api',router)
//这样请求 http://域名/api/xxx 才能访问 路由模块的路由了
// 基础路由
app.get('/', (req, res) => {
res.send('欢迎来到Express服务器!');
});
// 启动服务器
app.listen(PORT, () => {
console.log(`服务器运行在 http://localhost:${PORT}`);
});
Express 》》CORS 中间件 跨域问题
//cors 是express的一个第三方中间件,通过它 可以解决 跨域问题
// cors 中间件 使用步骤如下
1. 安装cors 中间件
npm i cors
2. 导入中间件
const cors = require('cors')
3. 注册中间件 在路由之前 注册
app.use(cors())
//CORS响应头
// Access-Control-Allow-Origin
// Access-Control-Allow-Origin:<origin> | *
参数:origin 指定允许访问该资源的外域URL
* 代表全部准许
res.setHeader('Access-Control-Allow-Origin','http://xxxx')
res.setHeader('Access-Control-Allow-Origin','*')
// Access-Control-Allow-Headers
// 默认情况下,CORS 仅支持客户端向服务器发送如下的 9个 请求头
1. Accept
2. Accept-Language
3. Content-Language
4. DPR
5. Downlink
6. Save-Data
7. Viewport-Width
8. Width
9. Content-Type(值仅限于 text/plain,multiparty/form-data,application/x-www-urlencoded 三者之一)
如果客户端向服务器发送了额外的请求头信息,则需要在服务端,
通过 Access-Control-Allow-Headers 对额外的请求头进行声明,否则这次请求会失败
//允许考核的额外向服务器发送 Content-Type 请求头和 X-Custom-Header 请求头
// 注意 注意 注意 多个请求头之间 用英文逗号进行分割
res.setHeader('Access-Control-Allow-Header','Content-Type,X-Custom-Header')
// Access-Control-Allow-Methods
默认情况下,CORS 仅支持 客户端 发送 GET 、POST、HEAD请求
如果客户端希望通过PUT、DELETE等方式请求服务器的资源,则需要在服务端,
通过 Access-Control-Allow-Methods 来指名实际请求准予Htpp方法
// 只允许 POST、GET、DELETE、HEAD 请求
res.setHeader('Access-Control-Allow-Methods','POST、GET、DELETE、HEAD')
// 允许所有 HTTP 请求方法
res.setHeader('Access-Control-Allow-Methods','*')
Express》》Session认证
# 要安装 express-session 中间件
npm i express-session
# 导入 express-session 中间件
const session = require('express-session')
# 注册 express-session 中间件
app.use(session({
secret:'xxxx', // 加密的密钥, 可以任意字符串
resave: false, // 固定写法
saveUninitialized : true // 固定写法
}))
# 写入session 配置了 express-session中间件 req就会出现 session
req.session.属性 = 'xxxx'
# 获取 session
const info = req.session.属性
# 清空 session
req.session.destroy()
const express = require('express');
const session = require('express-session')
const app = express();
const PORT = 9090;
app.use(express.static('./public'))
app.use(express.urlencoded({extended:false}))
app.use(express.json())
app.use(session({
secret:'abc123',
resave:false,
saveUninitialized:true
}))
// 处理 POST /home 请求的路由处理器
// 当express-session中间件配置成功后,即可通过 req.session 来 操作 session对象
app.post('/home', function (req, res) {
if(req.body.username !="xxx" || req.body.password !='##'){
return res.send({
status:1,
msg:'登录失败'
})
}
req.session.user = req.body //将用户的信息,存储到Session
req.session.islogin = ture //将用户的登录状态,存储到Session
res.send({
status:0,
msg:'登录成功'
});
});
// 处理 GET /profile 请求的路由处理器
app.get('/profile', function (req, res) {
if(!req.session.islogin)
{
return res.send({
status:1,
msg:'fail'
})
}
res.send({
status:0,
msg:'欢迎访问个人资料页面!',
username:req.session.use.username
});
});
// 启动服务器
app.listen(PORT, () => {
console.log(`服务器运行在 http://localhost:${PORT}`);
});