Express入门
Express 的作用和 Node.js 内置的 http 模块类似,是专门用来创建 Web 服务器的。
使用 Express,我们可以方便、快速的创建 Web 网站的服务器或 API 接口的服务器。
1、基本配置:
//1、导入express const express = require("express"); //2、实例化 const WebServer = express(); //3、调用并启动服务器 WebServer.listen(80, () => { console.log("启动"); });
2、get/post
send发送、query参数、params动态参数
//get。req请求对象,res响应对象 WebServer.get("/:id", (req, res) => { //发送JSON res.send({ name: "jacky", age: "18" }); //获取动态参数,匹配:后的值 //localhost/1 console.log(req.params); //{id:'1'} }); //post WebServer.post("/", (req, res) => { //发送文本 res.send("jacky"); //获取参数,返回对象 //localhost?a=1 console.log(req.query); //{a:'1'} });
3、资源托管
express.static()创建一个静态资源服务器。Express 在指定的静态目录中查找文件,并对外提供资源的访问路径。 因此,存放静态文件的目录名不会出现在 URL 中。
如果希望目录显示,则在express.static()的调用函数.use内添加参数,该参数其实可以是多级路由
如果要托管多个静态资源,只需要多次调用express.static()即可,先写的先查找
//1、导入express const express = require("express"); //2、实例化 const WebServer = express(); //3、创建托管 WebServer.use('/material',express.static('../素材')) //4、调用并启动服务器 WebServer.listen(80, () => { console.log("启动"); }); //可以随时改变url从而获取不同的文件
4、路由匹配
Express 中的路由分 3 部分组成,分别是请求的类型、请求的 URL 地址、处理函数,格式如下:
WebServer.method(path, handler)/WebServer.get('/', ()=>{ } )
在匹配时,会按照路由的顺序进行匹配,如果请求类型和请求的 URL 同时匹配成功,则 Express 会将这次请求,转交给对应的 function 函数进行处理。
5、路由模块化
为了防止路由过多而造成文件臃肿,一般会把路由单独抽取成文件,挂载到router上,然后exporst和require
//server.js const express = require("express"); const WebServer = express(); //导入路由模块 const userRouter = require("./router"); //注册路由模块 WebServer.use(userRouter); WebServer.listen(80, () => { console.log("服务器启动,http://localhost"); }); //router.js const express = require("express") //调用 express.Router() 函数创建路由对象,挂载到router上 const router = express.Router() router.get('/',()=>{ console.log('get'); }) router.post('/',()=>{ console.log('post'); }) module.exports = router
6、中间件:业务流程的中间处理环节
1、Express中间件:当一个请求到达 Express 的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理。
其本质就是处理函数:中间件函数的形参列表中,必须包含 next 参数。而路由处理函数中只包含 req 和 res。
多个中间件之间,共享同一份 req 和 res。基于这样的特性,我们可以在上游的中间件中,统一为 req 或 res 对象添加自定义的属性或方法,供下游的中间件或路由进行使用。
2、next():next 函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由。
3、全局生效中间件
客户端发起的任何请求,到达服务器之后,都会先触发的中间件,叫做全局生效的中间件。使用WebServer(app).use(中间件名称)
一定要在路由之前注册中间件
4、多个全局中间件流转
使用 app.use() 连续定义多个全局中间件。客户端请求到达服务器之后,会按照中间件定义的先后顺序依次进行调用
const express = require("express"); const app = express(); //全局中间件1 app.use((req, res, next) => { //该中间件获取系统时间 let time = Date.now(); //req挂载 req.startTime = time; //流转 next(); }); //全局中间件2 app.use((req, res, next) => { //该中间件获取上一轮的系统时间进行操作 req.startTime = req.startTime + "二次处理"; //流转 next(); }); //响应 app.get("/", (req, res) => { res.send("" + req.startTime); //1651111.....二次处理 }); app.listen(80, () => { console.log("Server has been started in http://localhost:80"); });
5、局部中间件
不使用 app.use() 定义的中间件,叫做局部生效的中间件
const partMid = (req, res, next) => { req.partStr = "局部中间件,其他路径无效"; next(); }; app.get("/", partMid, (req, res) => { let str = req.partStr ? req.partStr : "局部中间件未生效"; res.send(str); //局部中间件,其他路径无效 }); app.get("/user", (req, res) => { let str = req.partStr ? req.partStr : "局部中间件未生效"; res.send(str); //局部中间件未生效 });
6、多个局部中间件,逗号分割或者用数组,顺序从前到后
app.get("/", partMid1, partMid2, (req, res) => { app.get("/", [partMid1, partMid2], (req, res) => { let str = req.partStr ? req.partStr : "局部中间件未生效"; res.send(str); //局部中间件,其他路径无效 });
7、express分类:
- 应用级别的中间件:通过 app.use() 或 app.get() 或 app.post() ,绑定到 app 实例上的中间件
- 路由级别的中间件:绑定到 express.Router() 实例上的中间件
- 错误级别的中间件:专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题。错误级别中间件的function 处理函数中,必须有 4 个形参,形参顺序从前到后,分别是 (err, req, res, next)。错误级别的中间件,必须注册在所有路由之后
const express = require("express"); const app = express(); app.get("/", (req, res) => { throw new Error("500"); res.send('success') }); //错误中间件,需要定义在组件之后 app.use((err, req, res, next)=>{ res.send(err.message) }) app.listen(80,()=>{})
- Express 内置的中间件:
- express.static 快速托管静态资源的内置中间件,例如: HTML 文件、图片、CSS 样式等(无兼容性)
- express.json 解析 JSON 格式的请求体数据(有兼容性,仅在 4.16.0+ 版本中可用)
- express.urlencoded(option) 解析 URL-encoded 格式的请求体数据(有兼容性,仅在 4.16.0+ 版本中可用)选项options参数包含各种属性,例如扩展,膨胀,限制,验证等
//配置解析中间件 app.use(express.json()) app.use(express.urlencoded({extended:false})) app.post('/',(req, res)=>{ console.log(req.body); res.send('ok') })
- 第三方的中间件(自定义中间件):需要了解一些内置的事件,比如req的on绑定事件(比如data事件、end事件)
app.use((req, res, next)=>{ let str = '' //req的data事件 req.on('data',(chunk)=>{ //由于chunk是分块的,因此需要拼接才可获得一次完整的内容 str += chunk }) //当请求接收完成,自动触发end事件 req.on('end',()=>{ const body = qs.parse(str) req.body = body next() }) })
7、接口跨域:
1、CORS:CORS (Cross-Origin Resource Sharing,跨域资源共享)由一系列 HTTP 响应头组成,这些 HTTP 响应头决定浏览器是否阻止前端 JS 代码跨域获取资源
CORS响应头:
-
Access-Control-Allow-Origin:origin 参数的值指定了允许访问该资源的外域 URL,可通配*允许任何外域,也可以具体域名接受指定来源请求
-
Access-Control-Allow-Headers:默认情况下,CORS 仅支持客户端向服务器发送 9 个请求头,如果客户端向服务器发送了额外的请求头信息,则需要在服务器端对额外的请求头进行声明,否则这次请求会失败
-
Access-Control-Allow-Methods:如果客户端希望通过 PUT、DELETE 等方式请求服务器的资源,则需要在服务器端指明实际请求所允许使用的 HTTP 方法。可通配*允许任何请求,也可以具体请求
res.setHeader('Access-Control-Allow-Origin','*') res.setHeader('Access-Control-Allow-Headers', 'Content-Type') res.setHeader('Access-Control-Allow-Methods', '*')
注意点:
- CORS 主要在服务器端进行配置。客户端浏览器无须做任何额外的配置,即可请求开启了 CORS 的接口。
- CORS 在浏览器中有兼容性。只有支持 XMLHttpRequest Level2 的浏览器,才能正常访问开启了 CORS 的服务端接口(例如:IE10+、Chrome4+、FireFox3.5+)。
请求分类:简单请求(get、post、head,且无自定义头)和预检请求(其他请求类型如put等,有自定义头)
在浏览器与服务器正式通信之前,浏览器会先发送 OPTION 请求进行预检,以获知服务器是否允许该实际请求,所以这一次的 OPTION 请求称为“预检请求”。服务器成功响应预检请求后,才会发送真正的请求,并且携带真实数据。相比于简单请求的一次请求,预检请求会发送两次请求
const router = require('./router') const cors = require('cors') //在路由之前调用cors app.use(cors()) app.use('/api', router)
2、JSONP(只支持get):浏览器端通过 <script> 标签的 src 属性,请求服务器上的数据,同时,服务器返回一个函数的调用。这种请求数据的方式叫做 JSONP
8、node操作mysql
npm i mysql
const mysql = require('mysql') const db = mysql.createPool({ host: 'local', user: 'root', password: '123456', database: 'my_db' }) db.query('select 1', (err, res)=>{ if (err) { return console.log(err.message); } console.log(res); })