什么是跨域
只要协议、域名、端口有任何一个不同,都被当作是不同的域,对于端口和协议的不同只能通过后端来解决。浏览器一般情况下一个页面不能访问另外一个页面的脚本信息。
跨域的实现方法
跨域的实现方法有如下几种
JSONP
JSONP是JSON padding的简写,是应用JSON的一种新方法,在web服务中非常流行,JSONP看起来和JSON差不多,只不过是被包含在函数中的JSON。类似下面这样
callback({"name": "Nicolas" })
JSON由两部分组成:回调函数和数据,回调函数是当页面响应的时候页面调用的数据。回调函数的名字一般在请求中指定的。而数据就是传入回调函数的JSON数据。比如
http://jrg.com/index.html?callback=handler
这里指定的回调函数名字就是handler()。
JSONP是通过动态<script>标签来使用的,使用时候可以为src属性指定一个跨域URL。<script>元素和<img>
元素类似,都有能力不受限制从其他域中加载资料。又因为JSONP是有效的javascript代码,因此在加载完成之后,就会立即执行。比如下面例子
function handleResponse(response){
console.log("You`re at IP address" + response.ip + ", which is in"
+ response.city + ", " + response.region_name);
}
var script = document.createElement("script");
srcipt.src = "htt[://freegeoip.net/json/?callback=handleResponse";
document.body.insertBefore(script, document.body.firstChild);
这个例子通过查询地理位置定位服务来显示Ip和位置信息。
JSONP在开发人员中非常流行,主要原因是JSONP简单易用,与图像ping相比,它的优点在于可以直接访问相应文本,支持在浏览器与服务器之间的双向通信,但是它也有不足的地方。
不足的地方体现在两个方面,首先JSONP从其他域中加载代码执行,如果其他域不安全,很有可能在响应中夹带着恶意代码,而此时出了完全放弃JSONP调用之外,没有办法追究。其次要确定JSONP请求是否失败并不容易。虽然HTML5给<script>元素新增了一个onerror事件处理程序,但是目前没有得到任何浏览器的支持。为此,开发人员不得不使用计时器检测指定时间是否收到响应。
具体例子如下
//前端
<html>
<head>
<style>
.container{
width: 900px;
margin: 0 auto;
}
</style>
</head>
<body>
<div class = "container">
<ul class = "news">
<li>第11日前瞻:中国冲击4金 博尔特再战</li>
<li>双力争会师决赛</li>
<li>女排将死磕巴西</li>
</ul>
<button class ="switch">换一组</button>
</div>
</boyd>
<script>
var btn = document.querySelector(".switch");
var container = document.querySelector(".news")
btn.addEventListener("click", function(){
var script = document.createElement("script");
script.src = 'http://localhost:8080/getNews?callback=appendHtml';
document.head.appendChild(script);
document.head.removeChild(script);
})
function appendHtml(news){
var html = '';
for(var i = 0; i < news.length; i++){
html += '<li>' + news[i] + '</li>';
console.log(html);
container.innerHTML = html;
}
}
</script>
</html>
//后端
app.get('/getNews', function(req, res){
var news =[
"第11日前瞻:中国冲击4金 博尔特再战200米羽球",
"正直播柴飚/洪炜出战 男双力争会师决赛",
"女排将死磕巴西!郎平安排男陪练模仿对方核心",
"没有中国选手和巨星的110米栏 我们还看吗?",
"中英上演奥运金牌大战",
"博彩赔率挺中国夺回第二纽约时报:中国因对手服禁药而丢失的奖牌最多",
"最“出柜”奥运?同性之爱闪耀里约",
"下跪拜谢与洪荒之力一样 都是真情流露"
]
var data = [];
for(var i = 0; i < 3; i++){
var index = parseInt(Math.random() * (news.length));
data.push(news[index]);
news.splice(index, 1);
}
var cb = req.query.callback
if(cb){
res.send(cb + '('+ JSON.stringify(data) + ')');
}else{
res.send(data);
}
})
CORS(cross-origin-resource-sharing)
CORS是cross-origin-resrouce-sharing的缩写,定义了在必须访问跨域资源时,浏览器与服务器之间如何沟通,CORS后面的思想是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求是成功还是失败。
比如一个简单的使用GET和POST发送的请求,它没有自定义头部,主体内容是text/plain。在发送请求的时候,必须给它附加一个额外的origin头部,其中包含请求页面的信息,以便服务器根据这个头部来决定是否给予响应。下面是origin头部的一个示例。
origin: http://www.jirengu.com
如果服务器认为这个请求可以接收,就在access-control-allow-origin头部中回发相同的源信息(如果是公共资源,可以回发"*")。例如
Access-Control-Allow-Origin:http://www.jirengu.com
如果没有这个头部,或者有这个头部但是源信息不匹配,浏览器就会驳回请求。正常情况下,浏览器会处理这个请求。请求和响应都不包含cookie信息。
具体例子如下
//前端
<html>
<head>
<style>
.container{
width: 900px;
margin: 0 auto;
}
</style>
</head>
<body>
<div class = "container">
<ul class = "news">
<li>第11日前瞻:中国冲击4金 博尔特再战</li>
<li>双力争会师决赛</li>
<li>女排将死磕巴西</li>
</ul>
<button class ="switch">换一组</button>
</div>
</boyd>
<script>
var btn = document.querySelector(".switch");
var container = document.querySelector(".news")
btn.addEventListener('click', function(){
var xhr = new XMLHttpRequest();
xhr.open('get', 'http://localhost:8080/getNews', true);
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
var result = JSON.parse(xhr.responseText);
var html ='';
for(var i = 0; i < result.length; i++){
html += '<li>' + result[i] + '</li>';
container.innerHTML = html;
}
}
}
})
</script>
</html>
//后端
app.get('/getNews', function(req, res){
var news = [
"第11日前瞻:中国冲击4金 博尔特再战200米羽球",
"正直播柴飚/洪炜出战 男双力争会师决赛",
"女排将死磕巴西!郎平安排男陪练模仿对方核心",
"没有中国选手和巨星的110米栏 我们还看吗?",
"中英上演奥运金牌大战",
"博彩赔率挺中国夺回第二纽约时报:中国因对手服禁药而丢失的奖牌最多",
"最“出柜”奥运?同性之爱闪耀里约",
"下跪拜谢与洪荒之力一样 都是真情流露"
];
var data = []
for(var i = 0; i < 3; i++){
var index = parseInt(Math.random() * news.length);
data.push(news[index]);
news.splice(news[index], 1);
}
res.header("Access-Control-Allow-Origin", "*");
res.send(data);
});
降域
//a部分
<html>
<style>
.ct{
width: 910px;
margin: auto;
}
.main{
float: left;
width: 450px;
height: 300px;
border: 1px solid #ccc;
}
.main input{
margin: 20px;
width: 200px;
}
.iframe{
float: right;
}
iframe{
width: 450px;
height: 300px;
border: 1px dashed #ccc;
}
</style>
<div class="ct">
<h1>使用降域实现跨域</h1>
<div class="main">
<input type="text" placeholder="http://localhost:8080/a.html">
</div>
<iframe src="http://localhost:8080/b.html" frameborder="0" ></iframe>
</div>
<script>
var ipt = document.querySelector('.main input');
ipt.addEventListener('input', function(){
window.frames[0].document.querySelector('input').value = this.value;
})
document.domain = "hello.com"
</script>
</html>
//b部分
<html>
<style>
html,body{
margin: 0;
}
input{
margin: 20px;
width: 200px;
}
</style>
<input id="input" type="text" placeholder="http://localhost:8080/b.html">
<script>
// URL: http://b.jrg.com:8080/b.html
var ipt = document.querySelector('#input');
ipt.addEventListener('input', function(){
window.parent.document.querySelector('input').value = this.value;
})
document.domain = 'hello.com';
</script>
</html>