Express是一个基于Node.js的Web开发框架,专门用来创建Web服务器,本质就是一个npm上的第三方包。
Express可以快速创建两种服务器:
# 在项目中下载Express包
npm i [email protected]
//1、导入express
const express=require('express');
//2、创建Web服务器
const app=express();
//3、启动Web服务器,调用app.listen(端口号,启动成功后的回调函数)
app.listen(80,()=>{
console.log('express server running at http://127.0.0.1')
});
//监听GET请求
//参数1:客户端请求的URL地址
//参数2:请求对应的处理函数。
// req:请求对象(包含了与请求相关的属性和方法)
// res:响应对象(包含了与响应相关的属性和方法)
app.get('/user',(req,res)=>{
//把内容响应给客户端
res.send({name:'25',age:20,gender:'男'});//JSON对象
})
//监听POST请求
//参数与app.get()相同
app.post('/user',(req,res)=>{
//把内容响应给客户端
res.send('请求成功');//文本字符串
})
//获取URL中携带的查询参数 req.query
app.get('/',(req,res)=>{//http://127.0.0.1/?name=zs&age=20
//通过req.query可以获取到客户端发送过来的查询参数
//注意:默认情况下,req.query是一个空对象
res.send(req.query);
})
//获取URL中的动态参数 req.params
//这里的:id和:name是动态参数
app.get('/user/:id/:name',(req,res)=>{//http://127.0.0.1/user/123/zs
//req.params是动态匹配到的URL参数
//注意:默认情况下,req.params是一个空对象
res.send(req.params);
})
Express在指定的静态目录中查找文件,并对外提供资源的访问路径。
存放静态文件的目录名不会出现在URL中。
访问静态资源文件时,express.static()函数会根据目录的添加顺序查找所需的文件。
const express=require('express');
const app=express();
//在这里,调用express.static()方法,快速对外提供静态资源
//要托管多个静态资源目录,需多次调用express.static()
//http://127.0.0.1/index.html
app.use(express.static('./clock')); //项目根目录下有一静态资源文件夹clock
app.use(express.static('./file')); //项目根目录下有一静态资源文件夹file
//挂载路径前缀
//http://127.0.0.1/public/index.html
app.use('/public',express.static('./public')); //项目根目录下有一静态资源文件夹public
app.listen(80,()=>{
console.log('express server running at http://127.0.0.1')
});
使用nodemon可以监听项目文件的变动,当代码被修改后,nodemon会自动帮我们重启项目。
# 安装nodemon
# 全局安装需要管理员权限,所以前面加sudo
sudo npm install -g nodemon
# 使用nodemon
# 用nodemon替代node执行项目的js文件
nodemon 1.js
路由是客户端的请求与服务器处理函数之间的映射关系。
Express中的路由分三部分组成:(1)请求类型(2)请求的URL地址(3)处理函数。
1. 路由的匹配过程
每当一个请求到达服务器,需先经路由的匹配,匹配成功后调用对应的处理函数。
匹配会(1)按照路由的顺序进行,(2)若请求类型和请求的URL地址同时匹配成功,Express会将这次请求转交给对应的function函数进行处理。
2.路由的使用
(1)最简单用法:把路由挂载到app上【代码量太多,不方便管理,几乎不用】
const express=require('express');
const app=express();
//挂载路由
app.get('/',(req,res)=>{
res.send('Hello GET!');
})
app.post('/',(req,res)=>{
res.send('Hello POST!');
})
app.listen(80,()=>{
console.log('express server running at http://127.0.0.1')
});
(2)模块化路由:将路由抽离为单独的模块【推荐使用!】
const express=require('express');
const app=express();
//1、导入路由模块
const router= require('./2.js');
//2、注册路由模块
app.use(router);
//注意: app.use()函数的作用就是注册全局中间件!
//为路由模块添加前缀: app.use('/api',router);
app.listen(80,()=>{
console.log('express server running at http://127.0.0.1')
});
//这是路由模块 2.js文件
//1、导入express
const express=require('express');
const res = require('express/lib/response');
//2、创建路由对象
const router=express.Router();
//3、挂载具体路由
router.get('/user/list',(req,res)=>{
res.send('Get user list.');
})
router.post('/user/add',(req,res)=>{
res.send('Add new user.');
})
//4、向外导出路由对象
module.exports=router;
当一个请求到达Express服务器后,可以连续调用多个中间件,从而对这次请求进行预处理。
(1)定义中间件函数
const express=require('express');
const app=express();
//定义一个最简单的中间件函数
const mw=function(req,res,next){
console.log("这是最简单的中间件函数");
next();//把流转关系,转交给下一个中间件或路由
}
//将mw注册为全局生效的中间件
app.use(mw);
app.listen(80,()=>{console.log('express server running at http://127.0.0.1')});
(2)全局生效的中间件
客户端发起任何请求到达服务器后,都会触发的中间件。
//定义全局中间件的简写形式
app.use(function(req,res,next){
console.log("调用了第一个全局中间件");
next();
})
//可以连续定义多个全局中间件
app.use(function(req,res,next){
console.log("调用了第二个全局中间件");
next();
})
(3)局部生效的中间件
不使用app.use()定义的中间件
const express=require('express');
const app=express();
const mw1=function(req,res,next){
console.log('调用了第一个全局生效的中间件');
next();
}
const mw2=function(req,res,next){
console.log('调用了第二个全局生效的中间件');
next();
}
//调用局部生效的中间件,可以同时使用多个局部生效的中间件
//也可以写为 app.get('/',[mw1,mw2],(req,res)=>{ res.send('Home page.')})
app.get('/',mw1,mw2,(req,res)=>{res.send('Home page.')})
app.get('/user',(req,res)=>{res.send('User page.')})
app.listen(80,()=>{console.log('express server running at http://127.0.0.1')});
(4)中间件的作用
多个中间件之间共享同一份req和res,可以在上游的中间件中统一为req或res对象添加自定义的属性或方法,供下游的中间件或路由进行使用。
const express=require('express');
const app=express();
app.use(function(req,res,next){
const time=Date.now();//获取请求到达服务器的时间
//为req对象挂载自定义属性,从而把时间共享给后面的所有路由
req.startTime=time;
next();
});
app.get('/',(req,res)=>{res.send('Home page.'+req.startTime)})
app.get('/user',(req,res)=>{res.send('User page.'+req.startTime)})
app.listen(80,()=>{console.log('express server running at http://127.0.0.1')});
(5)中间件的5个注意事项
(6)中间件的分类
const express=require('express');
const app=express();
app.get('/',(req,res)=>{
//人为的制造错误
throw new Error('服务器内部发生了错误');
res.send('Home page.');
})
//定义错误级别的中间件,捕获整个项目的异常错误,从而防止程序的崩溃
app.use((err,req,res,next)=>{
console.log('发生了错误:'+err.message);
res.send('Error'+err.message);
})
app.listen(80,()=>{console.log('express server running at http://127.0.0.1')});
const express=require('express');
const app=express();
//配置解析 application/json 格式数据的内置中间件
app.use(express.json());
//配置解析 application/x-www-form-urlencoded 格式数据的内置中间件
app.use(express.urlencoded({extended:false}));
app.post('/user',(req,res)=>{
//在服务器可以使用req.body接受客户端发送过来的请求体数据
//默认情况下,如果不配置解析表单数据的中间件,则req.body默认等于undefined
console.log(req.body);
res.send('ok');
})
app.listen(80,()=>{console.log('express server running at http://127.0.0.1')});
const express=require('express');
const app=express();
//配置解析表单数据的中间件
app.use(express.json());
app.use(express.urlencoded({extended:false}));
//一定要在路由之前配置cors中间件,从而解决接口跨域问题
const cors=require('cors');//使用前先用npm下载
app.use(cors());
//导入路由模块
const router=require('./2.js');
//把路由模块注册到app上
app.use('/api',router);
// http://127.0.0.1/api/get?name=zs&age=20&gender=男
app.listen(80,()=>{
console.log('express server running at http://127.0.0.1')
});
//这是API路由模块 2.js文件
const express=require('express');
const router=express.Router();
//在这里挂载对应的路由
//1、编写GET接口
router.get('/get',(req,res)=>{
//通过req.query获取客户端通过查询字符串,发送到服务器的数据
const query=req.query;
//调用res.send()方法向客户端响应处理的结果
res.send({
status:0, //0 表示处理成功,1 表示处理失败
msg:'GET请求成功', //状态的描述
data:query //需要响应给客户端的数据
})
})
//2、编写POST接口
router.post('/post',(req,res)=>{
//通过req.body获取请求体中包含的url-encoded格式的数据
const body=req.body;
res.send({
status:0,
msg:'POST请求成功',
data:body
})
})
module.exports=router;
协议、域名、端口号任何一项不同就存在跨域问题。
解决跨域问题的方案有两种:(1)CORS(主流的解决方案,推荐使用);(2)JSONP(有缺陷的解决方案,只支持GET请求)
(1)使用CORS中间件解决跨域问题的步骤
(2)CORS(跨域资源共享)由一系列HTTP响应头组成,它们决定浏览器是否阻止前端JS代码跨域获取资源。
(3)CORS响应头
(4)CORS请求的分类
(5)JSONP