同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。 如果两个页面的协议,端口(如果有指定)和主机都相同,则两个页面具有相同的源。我们也可以把它称为“协议/主机/端口 tuple”,或简单地叫做“tuple". ("tuple" ,“元”,是指一些事物组合在一起形成一个整体,比如(1,2)叫二元,(1,2,3)叫三元)
以上定义是MDN文档对同源问题的定义。运用到我们的实际判断当中时,通俗地讲就是 如果两个页面拥有相同的协议、域名和端口,那么这两个页面就属于同源,其中只要一个不同就是不同源。
但是我们在实际开发过程当中,往往存在向非同源的服务器端请求数据的情况,所以我们必须通过一定的方法解决这一问题,实现向非同源请求地址请求数据的功能。目前主要的解决方案如下:
Jsonp方案
服务器端代理请求方案
CORS方案
一、Jsonp解决方案
1.原理
Jsonp是json with padding的缩写。严格意义上讲,这种方案不属于Ajax的范畴,而是通过 <script> 标签的src属性能够向非同源服务器请求数据的特殊性绕过浏览器的同源策略,来模拟的Ajax请求。
将非同源服务器端的请求地址写在script标签的src属性中
<script src="http://localhost:8080/test?callback=fn"></script>
这种方案服务端相应数据必须是一个函数的调用,真正要发送给客户端的数据需要作为函数的调用参数
app.get('/test', (req, res) => {
const result = 'fn({name: "张三"})';
res.send(result);
});
需要在客户端全局作用域下定义函数fn()
在fn函数的内部对服务器端返回的数据进行处理
通过上面的四点我们可以看出,Jsonp方案只适用于GET请求方式,
2.解决方案
根据 <script> 标签请求的原理,对其中涉及的各项变量参数进行参数化,使我们能够以函数的方式调用请求方法,并通过参数形式传入我们请求相关的数据。我们对该方案进行函数封装,封装函数之后的代码如下:
function jsonp (options) {
// 动态创建script标签
var script = document.createElement('script');
// 拼接字符串的变量,将data当中传入的参数格式化为我们需要的格式
var params = '';
for (var attr in options.data) {
params += '&' + attr + '=' + options.data[attr];
}
// 随机生成一个成功之后调用函数的函数名字,避免函数名字覆盖
var fnName = 'myJsonp' + Math.random().toString().replace('.', '');
// fnName已经不是一个全局函数了,我们要想办法将它变成全局函数
window[fnName] = options.success;
// 为script标签添加src属性
script.src = options.url + '?callback=' + fnName + params;
// 将script标签追加到页面中
document.body.appendChild(script);
// 为script标签添加onload事件 添加请求处理成功之后的方法
script.onload = function () {
//删除<script>标签 以免造成页面标签冗余
document.body.removeChild(script);
}
}
调用函数方法,其中的对象参数即为上述封装函数当中的options形参:
jsonp({
// 请求地址
url: 'http://localhost:3001/better',
data:{
name:'Tyrone',
age:18
},
success: function (data) {
console.log(data)
}
})
二、服务端代理请求方案
1、原理
跨域问题的存在主要是浏览器端的同源策略,导致返回的数据无法接受。在服务端
便没有这样的约束,可以随意请求不同源的服务器上的数据。
那么我们很容易联想到让自己的服务器先把目标源的资源请求过来,再返回给我们的方案来解决跨域问题。
2、解决方案
下载第三方模块request
npm install request
在服务端添加如下代码
// 向其他服务器端请求数据的模块
const request = require('request');
//向自己的服务器端请求数据
app.get('/test', (req, res) => {
//在接收到请求之后向目标服务器发送服务端请求
request('http://localhost:8080/target', (err, response, body) => {
//将目标服务器返回的数据body发送给客户端
res.send(body);
})
});
三、CORS跨域资源共享方案
1、原理
CORS:全称Cross origin resource sharing(跨域资源共享)。它允许向跨域服务器发送Ajax请求,不同于Jsonp的模拟Ajax,它克服了Ajax只能同源请求的问题。
这种方案是比较简单的一种,但是由于在服务端配置授信请求源,这种方案只适用于能够自己设定服务器端的情况下。通过设定 res.header('Access-Control-Allow-Origin', 'http://localhost:8080') 来允许来自localhost:8080的请求。
2、解决方案
服务端设置
// 拦截所有请求
app.use((req, res, next) => {
// 1.允许哪些客户端访问我 * 代表允许所有的客户端访问我
// 注意:如果跨域请求中涉及到cookie信息传递,值不可以为*号 比如是具体的域名信息
res.header('Access-Control-Allow-Origin', 'http://localhost:3000')
// 2.允许客户端使用哪些请求方法访问我
res.header('Access-Control-Allow-Methods', 'get,post')
// 允许客户端发送跨域请求时携带cookie信息
res.header('Access-Control-Allow-Credentials', true);
next();
});
(网络资源整理而来)
网友评论