在前面的HTTP模块内容内容当中讲到这个跨域的问题,跨域就涉及到浏览器的同源策略,跨域只出现在浏览器当中,在浏览器当中去执行脚本的时候会进行一个同源检测,只有是同源的脚本才会被浏览器执行,不同源就是跨域,同源就是请求的url协议、域名、端口号要相同,只有相同的才能够互相访问,不同就会出现跨域问题。下面用一个简单的例子图示理解:
后端解决跨域
下面来回顾之前通过后端处理的方式解决跨域的问题;通过后端的设置来解决请求跨域的问题:
Access to XMLHttpRequest at 'http://127.0.0.1:3000/' from origin 'http://127.0.0.1:5500' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
http://127.0.0.1:5500发起请求http://127.0.0.1:3000/中的数据,协议相同,域名相同,端口号不同出现跨域请求的问题,通过后端的设置解决跨域的问题,在后端设置中设置以下属性:
Access-Control-Allow-Origin",'*'
Access-Control-Allow-Headers","X-Requested-With"
Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS"
那么在HTTP模块中已经具体的讲述,就不在赘述了;
cors中间件 解决跨域
上一篇内容讲到这个中间件,那么这里来用使用cors中间件来解决跨域问题,cors是Express的一个第三方中间件;cors(cross-origin-resource Sharing)意思就是跨域资源共享,是由一系列的HTTP响应头组成,这些HTTP响应头也就决定了浏览器是否要阻止前端的js脚本去跨域请求获取资源,CROS主要是在服务器进行配置的,客户端浏览器无须做任何额外的配置,就可以开启了CROS的接口,但CORS在浏览器中有兼容性,例如IE10+,Chrome4+,FireFox3.5+;下面就来安装和使用这个cors中间件:
1. 安装cors第三方中间件;
npm install cors
2. 导入cors第三方中间件使用;
const express = require('express');
const app = express();
const fs = require('fs');
const cors = require('cors');
app.use(cors());
app.get('/',function(req,res){
let data = fs.readFileSync(__dirname + '/全国行政区数据.json')
res.end(data);
})
app.listen('3000',function(){
console.log('Server Running || 127.0.0.1:3000');
})
3. 测试使用;
通过编写一个index.html页面发起ajax请求:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>全国行政区</title>
</head>
<body>
<div id='app'>
<h2>全国行政区</h2>
<ul class="city">
</ul>
</div>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
$.ajax({
url:'http://127.0.0.1:3000'
}).then(res=>{
const rs = JSON.parse(res);
for(const i in rs.result){
$('.city').append('<li>'+rs.result[i].name+'</li>');
}
})
</script>
</body>
</html>
如果不使用的话,将app.use(cors())内容人注视点然后打开浏览器来对比使用cors中间件后HTTP响应头(Response Hearders):
Access-Control-Allow-Orgin
Access-Control-Allow-Orgin: * 表示允许来自任何域的请求,当然了也可以进行一个IP的限制,限制在某个域名之下才能够访问,有如下形式:
res.setheader("Access-Control-Allow-Orgin":"*");
res.setheader("Access-Control-Allow-Orgin":"http://mp.csdn.net");
Access-Control-Allow-Headers
默认情况下,cors仅支持客户端向浏览器发送这(Accept、Accept-Language、Content-Langage、DPR、Downink、Save-Data、Viewport-Width、Width、Content-Type[value:text/plain、multipart/from-data、application/x-www-form-urlencded])9个请求头,如果客户端向服务器发送了额外的请求消息,则需要在服务器端通过Access-Control-Allow-Headers 对额外的请求进行声明,否则会请求失败;如下需要进行其他请求头设置:
res.setHeader('Access-Control-Allow-Headers','Content-Type,X-Custom-Header')
Access-Control-Allow-Methods
默认情况下,CORS仅支持客户端发起GET、POST、HEAD请求,如果客户端希望通过PUT、DELETE等方式请求服务器资源,则需要在服务器端,通过Access-Control-Allow-Methods来指明实际请求所允许使用的HTTP方法;
// 只允许post,get,head,delete
res.setHeader('Access-Control-Allow-Methods','POST,GET,HEAD,DELETE');
// 允许所有请求方式
res.setHeader('Access-Control-Allow-Methods','*');
cors请求分类
cors请求分为两种:简单请求和预检请求
简单请求
GET / POST / HEAD 这三种任意一种请求方式,同时HTTP头部信息不超过以下几种字段:无自定义头部字段、Accept、Accept-Language、Content-Langage、DPR、Downink、Save-Data、Viewport-Width、Width、Content-Type[value:text/plain、multipart/from-data、application/x-www-form-urlencded]
预检请求
请求除了 GET/POST/HEAD 这三种的其他请求METHOD类型,请求头包含自定义头部字段,向服务器发送application/json的数据;
在浏览器与服务器进行正式通信之前,浏览器会先发送OPTION请求进行预检,以获得服务器是否允许该实际请求,所以这次的OPTION请求称为 "预检请求",服务器成功响应预检请求后,才会发送真实的请求且携带真实数据。
区别:
在简单请求中,客户端与服务器之间只发生一次请求,而在预检请求中,客户端与服务器之间发生两次请求,OPTION预检请求成功之后才会发起真正的请求;
下面来进行测试:
1. 编写代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<body>
<button id="get">简单请求</button>
<button id="del">预检请求</button>
<script>
$('#get').on('click',function(){
$.ajax({
type:'GET',
url:'http://127.0.0.1:3000/get',
success:function(res){
console.log(res);
}
})
})
$('#del').on('click',function(){
$.ajax({
type:'DELETE',
url:'http://127.0.0.1:3000/del',
success:function(res){
console.log(res);
}
})
})
</script>
</body>
</html>
// Express - /routes/index.js
const express = require('express');
const router = express.Router();
router.get('/get',function(req,res){
res.send('success');
})
router.delete('/del',function(req,res){
res.send({
status:0,
msg:'success'
})
})
module.exports = router;
通过执行node命令将服务器启动:
通过编写request.html模拟客户端来点击按钮发起对应的请求:
(Chrome谷歌浏览器)
(Firefox火狐浏览器)
以上就是关于cors中间件的知识和解决跨域问题的全部内容了,下面来讲另外一种跨域方式JSONP.
JSONP接口 解决跨域
在前面中讲到了浏览器中的同源策源,需要访问的协议,域名和端口号要一致才能够进行跨域,但在HTML中,用过<script><img><link><video><aduio>这些标签中的一个src属性,通过这个属性可以访问到来自不同域的资源,这种请求方式就是JSONP,请求服务器上的数据,同时服务器返回一个函数的调用;JSONP不属于真正的Ajax请求,因为它没有XmlHttpRequest这个对象,同时JSONP仅支持GET请求,这也是JSONP的一个缺点,不支持其他POST、DELETE、HEAD等请求。
JSONP接口创建之前如果配置了CORS跨域资源共享,为了防止冲突需要在配置注册使用(app.use())CORS中间件之前声明JSONP的接口,否则JSONP接口会被处理成开启了CORS接口,如下:
const express = require('express');
const app = express();
const cors = require('cors');
app.get('/jsonp',function(req,res){
// jsonp具体实现
})
// 配置cors中间件
app.use(cors());
// CORS接口
app.get('/get',function(req,res){
// cors具体实现
})
下面来编写JSONP的接口:
// index.js
const express = require('express');
const app = express();
const cors = require('cors');
app.get('/jsonp',function(req,res){
const getInfo = req.query.callback;
// 模拟数据
const data = {
name:'syan123',
sex:'女',
age:18
}
const cbStr = `${getInfo}(${JSON.stringify(data)})`;
res.send(cbStr);
})
app.use(cors());
app.listen('3000',function(req,res){
console.log('Server Running || 127.0.0.1:3000');
})
通过 jquery 发起 JSONP 请求,当然这个地方讲jsonp的一个内容会有一些片面,那么如果有后续会在js当中去提及到,这里仅仅是将JSONP也是能够实现跨域的一种手段跟大家聊聊;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<body>
<button id="jsonp">jsonp</button>
<script>
$('#jsonp').on('click',function(){
$.ajax({
type:'get',
dataType:'jsonp',
// jsonpCallback:'syan',
url:'http://127.0.0.1:3000/jsonp',
success:function(res){
console.log(res);
}
})
})
</script>
</body>
</html>
通过客户端发送过来的回调函数的名字,可以通过req.query.callback,如果没有写callback方法,jquery会自动封装一个callback方法;
以上就是本篇关于接口实现跨域的全部内容,感谢大家的支持!