今天我们就从 Express 接口开始详细了解一下CORS和JSONP接口.
1. Express 接口
- 创建基本服务器
- 创建API路由模块
- 编写 GET / POST 接口
// app.js 文件
const express = require('express'); // 导入 express 模块
const app = express(); // 创建实例
const router = require('./router'); // 导入路由模块
app.use('/api', router); // 配置全局路由模块
app.use(express.urlencoded({ // 解析url-encoded数据
extended: false
}));
app.use(express.json()); // 解析json数据
app.listen(3000, () => { // 启动服务器
console.log('server running at http://127.0.0.1:3000');
})
// router.js 文件
const express = require('express'); // 导入 express
const router = express.Router(); // 实例路由对象
router.get('/user', (req, res) => { // get请求
res.send({
status: 0, // 状态
msg: '请求成功', // 描述信息
data: req.query // 响应数据
})
});
router.post('/list', (req, res) => { // post请求
res.send({
status: 0,
msg: '请求成功',
data: req.body
})
});
module.exports = router; // 将路由对象暴露出去
代码写完了,接下来可以去测试一下接口能不能用
在Postman中测试没有问题,在这里我就不演示了,下面我们在HTML页面中发送Ajax请求传入数据
$('.get').click(function () {
$.ajax({
method: 'GET',
url: 'http://127.0.0.1:3000/api/user',
data: {
username: 'ls',
age: 20
},
success: res => {
console.log(res);
}
})
});
$('.post').click(function () {
$.ajax({
method: 'POST',
url: 'http://127.0.0.1:3000/api/list',
data: {
bookname: '西游记',
author: '吴承恩'
},
success: res => {
console.log(res);
}
})
});
这时,就报了如上的一个错误,简单来说就是不支持跨域请求.那么我们该如何解决这个问题呢?
2. CORS 跨域资源共享
解决接口跨域问题的方案主要有两种:
- CORS (主流解决方案)
- JSONP (只支持get请求)
2.1 使用 CORS 中间件解决跨域问题
cors 是 Express 的一个第三方中间件,通过安装和配置 cors 中间件,可以很方便地解决跨域问题.方法如下:
- 运行 npm i cors 安装中间件
- 使用 const cors = require('cors') 导入中间件
- 在路由之前调用 app.use(cors()) 配置中间件
配置完成之后,就成功接收到服务器响应回来的数据了
2.2 什么是 CORS
跨域问题解决了,但是到底什么是 CORS 呢? 现在我们一起来深入了解一下.
CORS (Cross-Origin Resource Sharing , 跨域资源共享) 由一系列 HTTP 响应头组成,这些 HTTP 响应头决定浏览器是否阻止前端JS代码跨域获取资源.
浏览器的同源安全策略默认会阻止网页"跨域"获取资源.但如果接口服务器配置了 CORS 相关的 HTTP 响应头,就可以解除浏览器端的跨域访问限制.
2.3 CORS 的注意事项
- CORS 主要在服务器端进行配置.客户端浏览器无需做任何额外的配置,即可请求开启了 CORS 的接口.
- CORS 在浏览器中有兼容性.只有支持 XMLHttpRequest Level2 的浏览器,才能正常访问
接下来,我们来看看 CORS 有哪些响应头
2.3 CORS 响应头部 - Access-Control-Allow-Origin
Access-Control-Allow-Origin: <origin> | * ;
// 响应头部中可以携带一个 Access-Control-Allow-Origin 字段
// 其中,origin 参数的值指定了允许访问该资源的外域 URL
res.setHeader('Access-Control-Allow-Origin','*')
//如果指定了 Access-Control-Allow-Origin 字段的值为通配符 *,表示允许来自任何域的请求
2.4 CORS 响应头部 - Access-Control-Allow-Headers
默认情况下,CORS
仅
支持
客户端向服务器
发送如下的 9 个
请求头
:
Accept、Accept-Language、Content-Language、DPR、Downlink、Save-Data、Viewport-Width、Width 、 Content-Type (值仅限于 text/plain、multipart/form-data、application/x-www-form-urlencoded 三者之一)
如果客户端向服务器
发送了额外的请求头信息
,则需要在
服务器端
,通过 Access-Control-Allow-Headers
对额外的请求头进行声明
,否则这次请求会失败!
2.5 CORS 响应头部 - Access-Control-Allow-Methods
默认情况下,CORS 仅支持客户端发起 GET、POST、HEAD 请求。
如果客户端希望通过
PUT
、
DELETE
等方式请求服务器的资源,则需要在服务器端,通过Access-Control-Alow-Methods 来
指明实际请求所允许使用的 HTTP 方法
。
2.6 CORS请求的分类
客户端在请求 CORS 接口时,根据
请求方式
和
请求头
的不同,可以将 CORS 的请求分为两大类
1. 简单请求
同时满足以下两大条件的请求,就属于简单请求:
请求方式
:GET、POST、HEAD 三者之一
HTTP 头部信息
不超过以下几种字段:
无自定义头部字段
、Accept、Accept-Language、Content-Language、DPR、Downlink、Save-Data、Viewport-Width、Width 、Content-Type(只有三个值application/x-www-form-urlencoded、multipart/form-data、text/plain)
特点: 客户端与服务器之间只会发生一次请求
2. 预检请求
只要符合以下任意一个条件,就需要进行预检请求:
请求方式为
GET、POST、HEAD 之外的请求 Method 类型
请求头中
包含自定义头部字段
向服务器发送
了 application/json 格式的数据
在浏览器与服务器正式通信之前,浏览器会
先发送 OPTION 请求进行预检,以获知服务器是否允许该实际请求
,所以这一 次的 OPTION 请求称为“预检请求”。
服务器成功响应预检请求后,才会发送真正的请求,并且携带真实数据
。
特点: 客户端与服务器之间会发生两次请求,
OPTION 预检请求成功之后,才会发起真正的请求
。
3. JSONP 接口
概念: 浏览器端通过 <script> 标签的 src 属性,请求服务器上的数据,同时,服务器返回一个函数的调用。这种请求数据 的方式叫做 JSONP。
特点:
JSONP 不属于真正的 Ajax 请求,因为它没有使用 XMLHttpRequest 这个对象。
JSONP 仅支持 GET 请求,不支持 POST、PUT、DELETE 等请求。
3.1 创建 JSONP 接口的注意事项
如果项目中
已经配置了 CORS
跨域资源共享,为了
防止冲突
,
必须在配置 CORS 中间件之前声明 JSONP 的接口
。否则 JSONP 接口会被处理成开启了 CORS 的接口。
3.2 实现 JSONP 接口的步骤
- 获取客户端发送过来的回调函数的名字
- 得到通过JSONP形式发送给客户端的数据
- 将数据拼接出一个函数调用形式的字符串
- 将字符串响应给客户端的<script>标签进行解析执行
const express = require('express'); // 导入 express 模块
const app = express(); // 创建实例
app.get('/jsonp', (req, res) => {
const { // 解构赋值,把回调函数名解构出来
callback
} = req.query;
const obj = { // 数据
uname: 'zs',
age: 20,
hobby: 'paly computer'
};
res.send(`${callback}(${JSON.stringify(obj)})`); //发送函数的调用形式,将数据转换为
}) // JSON格式的字符串
const cors = require('cors'); // 导入cors
app.use(cors()); // 注册全局中间件
app.use(express.urlencoded({ // 解析url-encoded数据
extended: false
}));
app.use(express.json()); // 解析json数据
const router = require('./rou'); // 导入路由模块
app.use('/api', router); // 配置全局路由模块
app.listen(3000, () => { // 启动服务器
console.log('server running at http://127.0.0.1:3000');
})
3.3 在网页中发起JSONP请求
<script>
// 通过JQuery发送JSONP请求
$('.jsonp').click(function () {
$.ajax({
method: 'GET',
url: 'http://127.0.0.1:3000/jsonp',
dataType: 'jsonp',
success: res => {
console.log(res);
}
})
});
// 直接通过script标签的src属性请求数据
// function fn(res){
// console.log(res);
// }
</script>
<!-- <script src="http://127.0.0.1:3000/jsonp?callback=fn"></script> -->
CORS是后端写接口会用到的,前端只需要了解即可,明白在做什么事情.
JSONP的概念与特点我们需要记住,面试经常会问.