1.作用:
-
用来创建web服务器
2.创建web服务器的步骤:
-
导入http模块
-
创建一个web服务器的实例
-
监听客户端的请求
-
启动服务
3.req对象和res对象:
-
req请求对象,包含请求相关信息(请求方式,请求地址等)
-
res响应对象,包含响应相关信息:res.end(响应的内容);
4.解决响应中文乱码的问题:
-
设置响应头: res.setHeader('Content-Type', 'text/html; charset=utf-8')
5.Node中模块化:
-
模块化概念:将一个文件拆分成多个独立并且相互依赖的小模块
-
好处:①提高代码的复用性;②提高代码的可维护性;③可以实现按需加载
-
模块化分类:①内置模块:Node.js官方提高;②自定义模块:用户创建的每个js文件就是一个模块;③第三方模块:第三方开发的模块,下载安装之后才能使用
6.模块的加载(★★★★★):
-
使用require()方法加载需要的内置模块、用户自定义模块、第三方模块进行使用
-
使用require()方法加载其他模块时,会执行被加载模块中的代码
-
在使用require()加载用户自定义模块期间,可以省略.js后缀名
-
使用 require() 方法导入模块时,导入的结果,永远以module.exports 指向的对象为准
7.对外共享模块成员:
-
给module.exports对象上面挂载属性
-
让module.exports指向一个形象
-
给exports对象上面挂载属性
二、包(★★★★★):
1.使用步骤:
1.使用npm安装包 2.导入包 3.根据使用包的文档进行书写
2.npm包管理器:
1.安装包:npm i 包的名称或者是npm install 包的名称 2.卸载包:npm uninstall 包的名称 3.指定包的版本: npm i 包的名称@版本
3.包配置管理:
-
快速创建package.json命令(node init -y);
注意:只能在英文的目录下成功运行,目录不要出现中文,空格
-
dependencies节点:运行命令: npm i 包的名称。用来记录项目开发和上线需要用到的包
-
devDependencies 节点
三、express框架
1.创建web服务器:
//导入包
const express = require('express')
//创建服务器
const app = express()
//启动服务器
app.listen('3000',()=>{
console.log('http://localhost:3000')
})
2.监听get和set请求:
-
app.get(请求的url地址,请求对应的处理函数)
-
app.post(请求的url地址,请求对应的处理函数)
3.获取查询参数:
-
req.query,获取到的是对象
4.获取动态参数:
-
req.params ,获取到的是对象
5.托管静态资源:
-
app.use(express.static(指定的静态目录))
-
挂载路径前缀:app.use('/前缀名',express.static(指定的静态目录))
-
访问静态资源文件时,express.static()函数会根据目录的加载顺序查找所需的文件
四、express路由:
1.概念
-
客户端请求和服务器处理函数之间的映射关系
2.定义路由的语法:
-
app.get(url地址,请求处理函数)
-
app.post(url地址,请求处理函数)
3.路由的匹配:
-
按照定义的先后顺序进行匹配,请求类型和请求的URL同时匹配成功,才会调用对应的处理函数
4.路由模块化
4.1.定义路由:
//引入express
const express = require('express')
//创建路由
const router = express.Router()
//挂载路由
router.get("/api/getbooks", (req, res) => {
res.send("/api/getbooks被监听到了");
});
router.post("/addbooks",(req,res)=>{
res.send({
status:201,
message:"添加图书成功"
})
})
//导出路由
module.exports = router
4.2注册路由:
//导入路由 const router = reqiure('./3-router') //注册路由 app.use('/api',router)
五、express中间件:
1、概念:
-
业务流程的中间处理环节,是对请求的预处理
2、中间件语法格式:
//定义中间件
const kw = function(req,res,next){
console.log('中间件被触发了')
//一定要加,否则就无法执行下面的路由
next()
}
3、全局中间件
const express = require("express");
const app = express();
/**
* 中间件:
* 概念:业务的中间处理环节,,做请求的预处理
* 语法:(req,res,next)=>{next()}
* 位置:路由在路由之前定义并且注册中间件
* 注意:
* 一定要在中间件调用next(),进行流转关系的转移
* 如果不写,请求处理了,不会有响应
*/
// 定义中间件
// const kw = (req, res, next) => {
// console.log("我是中间件");
// //一定要在中间件调用next()
// next();
// };
// // 注册中间件
// app.use(kw);
// 简写方式
// 全局中间件(就是每一个路由,都要经过这个中间件)
app.use((req, res, next) => {
console.log("我是中间件1");
next();
});
app.use((req, res, next) => {
console.log("我是中间件2");
next();
});
// 挂载路由
app.get("/api/getbooks", (req, res) => {
res.send("获取图书成功");
});
app.post("/api/addbook", (req, res, next) => {
res.send("添加图书成功");
});
app.listen(3000, () => {
console.log("http://localhost:3000");
});
3.1注意点:每个请求都会经过这个中间件
4、局部中间件:
4.1、注意点:
-
一定要执行在路由之前,注册中间件
-
客户端发送过来的请求,可以连续调用多个中间件进行处理
-
执行完中间件的业务代码之后,不要忘记调用next()函数
-
为了防止代码逻辑混乱,调用next()函数后不要再写额外的代码
-
连续调用多个中间件时,多个中间之间,共享req和res对象
-
只有某个请求才会经过的中间件,定义在;路由处理函数的前面
4.2、完整代码:
const express = require("express");
const app = express();
/***
* 中间件的的分类:
* 全局中间件:每一个情求,都会经过这个全局的中间件
* 局部中间件:只有某个请求,才会经过中间件
*/
// 定义中间件
// 局部中间件(只有某个路由,才经过这个中间件)
const kw = (req, res, next) => {
console.log("我是中间件");
next();
};
const kw1 = (req, res, next) => {
console.log("我是中间件");
next();
};
// 挂载路由
app.get("/api/getbooks", [kw,kw1],(req, res) => {
res.send("获取图书成功");
});
app.post("/api/addbook", (req, res, next) => {
res.send("添加图书成功");
});
app.listen(3000, () => {
console.log("http://localhost:3000");
});
5、中间件分类
5.1、应用级别的中间件:
-
绑到app实例上的中间件
-
完整代码:
const express = require("express"); const app = express(); /** * 中间件: * 概念:业务的中间处理环节,,做请求的预处理 * 语法:(req,res,next)=>{next()} * 位置:路由在路由之前定义并且注册中间件 * 注意: * 一定要在中间件调用next(),进行流转关系的转移 * 如果不写,请求处理了,不会有响应 */ // 定义中间件 // const kw = (req, res, next) => { // console.log("我是中间件"); // //一定要在中间件调用next() // next(); // }; // // 注册中间件 // app.use(kw); // 简写方式 // 全局中间件(就是每一个路由,都要经过这个中间件) app.use((req, res, next) => { console.log("我是中间件1"); next(); }); app.use((req, res, next) => { console.log("我是中间件2"); next(); }); // 挂载路由 app.get("/api/getbooks", (req, res) => { res.send("获取图书成功"); }); app.post("/api/addbook", (req, res, next) => { res.send("添加图书成功"); }); app.listen(3000, () => { console.log("http://localhost:3000"); });
5.2、路由级别的中间件:
-
绑定到router实例上的中间件
5.3、错误级别的中间件:
-
作用:用来捕获整个项目中发生的异常错误,从而防止项目崩溃
-
格式:function(err,req,next){//处理}
-
注意:错误级别的中间件,必须要注册到所有路由之后
-
完整代码:
const express = require("express"); const app = express(); //需求:获取到请求到达服务器的时间 app.get("/api/getbooks", (req, res) => { const m = req.query.name.toUpperCase(); res.send("获取图书列表成功" + m); }); app.post("/api/addbook", (req, res) => { res.send("添加图书成功"); }); /** * 错误中间件: * 作用:用来捕获整个项目的异常,从而防止项目崩溃 * 格式:(err,req,res,next)=>{} * 位置: * 放到所有路由之后,来捕获异常 */ app.use((err, req, res, next) => { res.send("服务器错误" + err.message); }); app.listen(3000, () => { console.log("http://localhost:3000"); });
5.4、express内置的中间件:
-
express.json()中间件
//通过express.json()中间件,解析表单中JSON格式的数据 app.use(express.json())
-
express.urlencoded()中间件
-
完整代码:
const express = require("express"); const app = express(); //通过express.urlencoded()中间件,能够解析application/x-www-form-urlcoded数据格式 app.use( express.urlencoded({ extended: false, }) ); // 监听请求 app.post("/login", (req, res) => { // req.body获取的是客户端请求携带的参数(post请求方式携带的参数) // req.body在不配置中间件的情况下,获取到是的值是undefined // 配置了中间件之后,结果是一个对象 eg:{name:'zs',age:18} console.log(req.body); res.send("监听了"); }); app.listen(3000, () => { console.log("http://locaohost:3000"); });
-
-
express.static()中间件
六、跨域解决方法:
6.1、cors
-
概念:由一系列http响应头组成,http响应头决定浏览器是否阻止js代码跨域获取资源
-
在服务器端设置响应头
-
完整代码:
/*** * 跨域: * 概念:协议,域名,端口号有一个不一样就是跨域 * 原因:浏览器的同源策略,不允许请求非同源的资源 * 解决方法: * 【1】jsonp: * 原理:利用script标签的src属性进行跨域,传一个函数名给后台,后台返回的一个函数调用 * 缺点:只支持get请求,不支持post请求 * 配合:需要前后台配合完成 * 前端: * 1.定义一个全局函数 * 2.设置script标签的src,同时要传一个函数名给后台 * 后台: * 返回一个函数调用 * 【2】cors: 只需要后台完成 */ const express = require("express"); const app = express(); //配置中间件解决跨域 // app.use((req, res, next) => { // res.setHeader("Access-Control-Allow-Origin", "*"); // res.setHeader("Access-Control-Allow-Headers", "Content-Type"); // res.setHeader("Access-Control-Allow-Methods", "*"); // next(); // }); // 使用cors第三方包来解决跨域 const cors = require("cors"); //注册并使用 app.use(cors()); app.get("/api/get", (req, res) => { res.send("get请求被监听到了"); }); app.post("/api/post", (req, res) => { res.send("post请求被监听到了"); }); app.delete("/api/delete", (req, res) => { res.send("delete请求被监听到了"); }); // 启动服务器 app.listen(3000, () => { console.log("http://localhost:3000"); });
6.2、响应头字段:
-
Access-Control-Allow-Origin字段
//语法格式 Access-Control-Allow-Origin:<origin> | * origin参数的值指定了允许访问该资源的外域URL //限制访问资源的书写方式 res.setHeader('Access-Control-Allow-Origin','http://www.baidu.com') //允许访问任何资源的书写方式 res.setHeader('Access-Control-Allow-Origin','*')
-
Access-Control-Allow-Headers字段
//允许客户端外向服务器发送 Content-Type 请求头和X-Custom-Header请求头 //注意:多个请求头之间使用英文的逗号分割 //语法格式: res.setHeader('Access-Control-Allow-Headers','Content-Type,X-Custom-Header')
-
Access-Control-Allow-Methods字段
//只允许POST、GET、DELETE、HEAD请求方法 res.setHeader('Access-Control-Allow-Headers','POST,GET,DELETE,HEAD') //允许所有的HTTP请求方法 res.setHeader('Access-Control-Allow-Headers','*')
6.3、请求分类:
-
简单请求:客户端和服务器之间只发生一次请求
-
预检请求:客户端和服务器之间会发生两次请求,OPTION预检请求成功之后,才会发起真正的请求
-
预检的条件:① 请求方式是GET,POST,HEAD之外的请求Method;②请求头中包含自定义头部字段;③向服务器发送了application/json格式的数据
6.4、jsonp:
-
特点:①只支持get请求,不支持post,put等其他的请求;②jsonp不是真正的ajax请求;
-
原理:通过script标签的src属性,传给一个函数名给后台,后台返回一个函数调用
-
完整代码:
const express = require("express"); const app = express(); // 挂载路由 app.get("/api/jsonp", (req, res) => { /** * 返回是一个函数调用jQueryxxx({}) * 思路: * 1.获取客户端发送过来的函数名req.query.callback * 2.自己定义一个数据 * 3.拼接一个函数的调用形式 * 4.响应回去 */ //1.获取客户端发送过来的函数名req.query.callback const { callback } = req.query; // 2.自己定义一个数据 const obj = { name: "zs", age: 18 }; //3.拼接一个函数的调用形式 const str = `${callback}(${JSON.stringify(obj)})`; res.send(str); }); app.listen(3000, () => { console.log("http://localhost:3000"); });