node.js-express中间件/跨域问题
中间件
当一个请求到达express的服务器之后,可以连续第爱用多个中间件,从而对此次请求进行预处理 本质上是一个function处理 函数 注意:中间件函数的形参列表中,必须包含next,二路由只有req和res。 next函数是实现多个中间件连续调用的关键,他表示把流转关系转交给下一个中间件和路由。 全局中间件const express = require('express');
const app = express();
//定义一个简单的中间件函数
const mw = function (req, res, next) {
console.log('这是一个简单的中间件函数');
//把流转关系,转交给下一个中间件或路由
next();
}
//将mw注册为一个全局生效的中间件
app.use(mw);
app.get('/', (req, res) => {
console.log('调用了/');
res.send('home page')
});
app.get('/user', (req, res) => {
console.log('调用了/user');
res.send('user page')
})
app.listen(80, () => {
console.log('http://127.0.0.1');
})
postman测试
终端测试结果 http://127.0.0.1 这是一个简单的中间件函数 调用了/ 这是一个简单的中间件函数 调用了/user 中间件简化形式 app.use((req, res, next) => { console.log('这是一个中间件'); next(); })中间件的作用
多个中间件之间,共享同一份req和res。我们可以在上游的中间件中,统一为req和res对象添加自定义的属性和方法,恭下游的中间件和路由使用const express = require('express');
const app = express();
app.use((req, res, next) => {
//获取请求到达服务器的时间
const time = Date.now();
req.startTime = time;
console.log('这是一个中间件');
next();
})
app.get('/', (req, res) => {
console.log('调用了/');
res.send('home page' + req.startTime)
});
app.get('/user', (req, res) => {
console.log('调用了/user');
res.send('user page' + req.startTime)
})
app.listen(80, () => {
console.log('http://127.0.0.1');
})
定义多个全局中间件
连续多次调用中间件const express = require('express');
const { expr } = require('jquery');
const app = express();
app.use((req, res, next) => {
console.log('调用第一个中间件');
next();
})
app.use((req, res, next) => {
console.log('调用第二个中间件');
next();
})
app.get('/', (req, res) => {
res.send('home page')
})
app.listen(80, () => {
console.log('http://127.0.0.1');
})
postman测试
发送get请求
终端结果如下
[nodemon] starting `node 定义多个中间件.js`
http://127.0.0.1
调用第一个中间件
调用第二个中间件
局部生效的中间件
const express = require('express');
const app = express();
const mw1 = (req, res, next) => {
console.log('调用了局部生效的中间件');
}
app.get('/', mw1, (req, res) => {
res.send('home page');
});
app.get('/user', (req, res) => {
res.send('user page');
});
app.listen(80, () => {
console.log('http://127.0.0.1');
})
postman测试http://127.0.0.1/终端显示调用局部中间件
postman测试http://127.0.0.1/user,终端不显示调用局部中间件
定义多个局部中间件
const express = require('express');
const app = express();
const mw1 = (req, res, next) => {
console.log('调用了局部生效的中间件1');
next()
}
const mw2 = (req, res, next) => {
console.log('调用了局部生效的中间件2');
next()
}
app.get('/', mw1, mw2, (req, res) => {
res.send('home page');
});
app.get('/user', [mw1, mw2], (req, res) => {
res.send('user page');
});
app.listen(80, () => {
console.log('http://127.0.0.1');
})
postman测试http://127.0.0.1/
postman测试http://127.0.0.1/user
[nodemon] starting `node 1局部中间件.js`
http://127.0.0.1
调用了局部生效的中间件1
调用了局部生效的中间件2
调用了局部生效的中间件1
调用了局部生效的中间件2
中间件的分类
应用级别的中间件
绑定到app实例上的中间件,例如app.use(),app.get()等路由级别的中间件
绑定到router实例上的中间件,例如router.use(),router.get()等错误级别的中间件
用来捕获整个项目发送的异常错误,从而防止项目异常崩溃的问题。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');
})
postman测试
终端显示结果 [nodemon] starting `node 2演示错误级别的中间件.js` express server running at http://127.0.0.1 发生了错误服务器内部发生了错误!内置中间件
const express = require('express');
const app = express();
//通过express.json()来解析客户端发送过来的JSON格式的数据
app.use(express.json());
//通过express.urlencoded()这个中间件,解析表单中的url-encoded格式的数据。
app.use(express.urlencoded({ extended: false }))
app.post('/', (req, res) => {
//在服务器,可以使用req.body这个属性,来接收客服端发送过来的额请求数据
//默认情况,如果不配置解析表单数据的中间件,则req.body默认等于undefined
console.log(req.body);
res.send('ok')
});
app.post('/book', (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');
})
postman中进行调试测试
[nodemon] starting `node 3演示内置中间件.js` express server running at http://127.0.0.1 { name: 'ss', age: 20 } [nodemon] starting `node 3演示内置中间件.js` express server running at http://127.0.0.1 [Object: null prototype] { bookname: '生命', author: '美国人', publisher: '天津' } 第三方的中间件const express = require('express');
const app = express();
//导入解析数据的中间件 body-parser
const parser = require('body-parser');
//注册中间件
app.use(parser.urlencoded({ extended: false }))
app.post('/user', (req, res) => {
//没有配置任何解析表单数据的中间件,则req.body默认为undefined
console.log(req.body);
res.send('ok')
})
app.listen(80, () => {
console.log('express server running at http://127.0.0.1');
})
注意:express内置的express.urlencoded中间件,就是基于body-parser这个第三方中间件进一步封装出来了。
自定义中间件
const express = require('express');
const app = express();
//解析表单中间件
//导入自己的中间件模块
const customBodyParser = require('./6custom-body-parser');
//将自定义的中间件函数,注册为全局可用的中间件
app.use(customBodyParser);
app.post('/user', (req, res) => {
res.send(req.body);
})
app.listen(80, () => {
console.log('express server running at http://127.0.0.1');
})
封装函数模块
const qs = require('querystring');
const bodyParser = (req, res, next) => {
//定义一个字符串,专门用来存储客户端发送过来的请求体数据
let str = "";
req.on('data', (chunk) => {
str += chunk;
});
//监听req的end事件
req.on('end', () => {
// console.log(str);
//把字符串的请求体数据,解析成对象格式
const body = qs.parse(str);
//将解析出来的数据对象挂载为req.body
req.body = body;
next();
})
}
module.exports = bodyParser
使用Express写接口
//创建一个基本服务器 const express = require('express'); const app = express(); //配置解析表单数据的中间件 app.use(express.urlencoded({ extended: false })) //导入路由模块 const router = require('./8.路由模块'); //注册 app.use('/api', router); app.listen(80, () => { console.log('express server running at http://127.0.0.1'); })
路由模块
const express = require('express');
const router = express.Router();
//挂载对于的路由
router.get('/get', (req, res) => {
//通过req.query获取客户端通过查询字符串,发送到服务器的数据
const query = req.query;
//调用res.send方法,想客服端响应处理结果
res.send({
status: 0,//0成功,1失败
msg: 'GET 请求成功',
data: query//需要响应给客户端的数据
})
})
//定义post接口
router.post('/post', (req, res) => {
//通过req.body获取请求体中包含的url-encoded格式的数据
const body = req.body;
//调用res.send,向客户端响应结果
res.send({
status: 0,
msg: 'POST 请求成功',
data: body
})
})
module.exports = router;
postman测试结果
加入查询条件之后
接口跨域问题
解决端口跨域问题的方案主要有两种: CORS:推荐 JSON P:只支持GET请求 使用CORS中间件解决跨域问题//创建一个基本服务器 const express = require('express'); const app = express(); //配置解析表单数据的中间件 app.use(express.urlencoded({ extended: false })); //在路由之前,配置中间件 const cors = require('cors'); app.use(cors()); //导入路由模块 const router = require('./8.路由模块'); //注册 app.use('/api', router); app.listen(80, () => { console.log('express server running at http://172.20.10.3'); })
加入cors中间件之后,可以解决跨域问题
在浏览器中打开,进行get和post请求成功
预检请求
在浏览器与服务器正式通信之前,浏览器会先发送OPTION请求进行预检,以获知服务器是否允许该实际请求,所以这一次的OPTION请求称为“预检请求”,服务器成功相应预检请求后,才会发送正真的请求,并且携带真实数据。 简单请求和预检请求的区别 简单请求的特点:客户端与服务器之间只会发生一次请求 预检请求的特点:客户端与服务器之间会发生两次请求,OPTION预检请求成功之后,才会发起真正的请求。JSONP接口
//必须在cors之前创建jsonp接口 app.get('/api/jsonp', (req, res) => { }) //在路由之前,配置中间件 const cors = require('cors'); app.use(cors());
在网页中使用jquery发起jsonp请求
app.get('/api/jsonp', (req, res) => {
//得到函数的名称
const funcname = req.query.callback;
//定义要发送到客服端的数据对象
const data = { name: "ss", age: 20 };
//拼接以函数的调用
const scriptstr = funcname + '(' + JSON.stringify(data) + ')';
//把拼接的字符串,响应给客户端
res.send(scriptstr);
})
//3.为JSONP绑定事件 $("#btnJSONP").on('click', function () { $.ajax({ type: 'GET', url: 'http://172.20.10.3/api/jsonp', dataType: 'jsonp', success: function (res) { console.log(res); } }) })