跨域问题及常见解决方法
1.出现跨域问题是因为浏览器的同源策列限制,下面是MDN文档对浏览器同源策略的描述,简单来说就是:
同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)
浏览器的同源策略
同源策略是一个重要的安全策略,它用于限制一个origin的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。
同源的定义
如果两个 URL 的 protocol、port (en-US) (如果有指定的话)和 host 都相同的话,则这两个 URL 是同源。这个方案也被称为“协议/主机/端口元组”,或者直接是 “元组”。(“元组” 是指一组项目构成的整体,双重/三重/四重/五重/等的通用形式)。
2.四种常见解决跨域的方法:
一,CORS:
跨域资源共享,它允许浏览器向非同源服务器,发出XMLHttpRequest请求。它对一般请求和非一般请求的处理方式不同: 1、一般跨域请求(对服务器没有要求):只需服务器端设置Access-Control-Allow-Origin 2、非一般跨域请求(比如要请求时要携带cookie):前后端都需要设置。
一般跨域请求服务器设置代码: (1)Node.JS
const http = require('http');
const server = http.createServer();
const qs = require('querystring');
server.on('request', function(req, res) {
var postData = '';
// 数据块接收中
req.addListener('data', function(chunk) {
postData += chunk;
});
// 数据接收完毕
req.addListener('end', function() {
postData = qs.parse(postData);
// 跨域后台设置
res.writeHead(200, {
'Access-Control-Allow-Credentials': 'true', // 后端允许发送Cookie
'Access-Control-Allow-Origin': 'http://www.example.com', // 允许访问的域(协议+域名+端口)
});
res.end(JSON.stringify(postData));
});
});
server.listen('8080');
console.log('running at port 8080...');
复制代码
(2)PHP
<?php
header("Access-Control-Allow-Origin:*");
复制代码
如果要发送Cookie,Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie也无法读取服务器域名下的Cookie。
前端请求携带cookie代码:
(1)原生JavaScript
const xhr = new XMLHttpRequest();
// 前端设置是否带cookie
xhr.withCredentials = true;
};
复制代码
(2)axios
axios.defaults.withCredentials = true
复制代码
二,JSONP
JSONP 只支持get请求,不支持post请求。 核心思想:网页通过添加一个<scriot>
标签,向服务器请求 JSON 数据,服务器收到请求后,将数据放在一个指定名字的回调函数的参数位置传回来。
原生JavaScript代码:
<script src="http://example.php?callback=getData"></script>
// 向服务器发出请求,请求参数callback是下面定义的函数名字
// 处理服务器返回回调函数的数据
<script type="text/javascript">
function getData(res)
{
console.log(res.data)
}
</script>
复制代码
三,设置document.domain
因为浏览器是通过document.domain属性来检查两个页面是否同源,因此只要通过设置相同的document.domain,两个页面就可以共享Cookie(此方案仅限主域相同,子域不同的跨域应用场景。)
// 两个页面都设置
document.domain = 'test.com';
复制代码
四,跨文档通信 API:window.postMessage()
调用postMessage方法实现父窗口向子窗口发消息(子窗口同样可以通过该方法发送消息给父窗口)
var openWindow = window.open('http://test2.com', 'title');
// 父窗口向子窗口发消息(第一个参数代表发送的内容,第二个参数代表接收消息窗口的url)
openWindow.postMessage('Nice to meet you!', 'http://test2.com');
//调用message事件,监听对方发送的消息
// 监听 message 消息
window.addEventListener('message', function (e) {
console.log(e.source); // e.source 发送消息的窗口
console.log(e.origin); // e.origin 消息发向的网址
console.log(e.data); // e.data 发送的消息
},false);