之前遇到过跨域的问题,一直觉得很神秘,也没有多关注,就过去了,今天又看到几篇文章说跨域,闲来无事于是将其整理记录下来;
一些概念
先来阐述下几个概念:
跨域:是指浏览器对于JavaScript的同源策略限制,只要协议、域名、端口有任何一个不同,都被当作是不同的域,都不能执行或获取其他网站的资源;
姑且这么定义吧,举个简单例子,就是www.client.com网站上的程序不能从www.server.com网站上获取数据,如果强行获取,则会报出下面错误
有没有跨域,判断是不是属于跨域,可以参考下面:
CORS:CORS(Cross-Origin Resource Sharing)跨域资源共享,定义了必须在访问跨域资源时,浏览器与服务器应该如何沟通.CORS背后的基本思想就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是失败.
服务器端对于CORS的支持,主要就是通过设置Access-Control-Allow-Origin来进行的.如果浏览器检测到相应的设置,就可以允许Ajax进行跨域的访问.
解决方法
Solution 1:服务端程序解决
如果是双方预定沟通好请求允许数据,可以在服务端添加header头来解决
1 2 3
| header( "Access-Control-Allow-Origin:*" );
header( "Access-Control-Allow-Methods:POST,GET" );
|
看下面的例子:
客户端 www.client.com/cliend.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
<!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html;charset=utf-8"> <title> 跨域测试 </title> <script src="//code.jquery.com/jquery-1.11.3.min.js"></script> </head>
<body> <button style="width:100px">click client</button> <script type="text/javascript"> $("button").click(function () { $.ajax({ url: "http://www.server.com/server.php", type: "post", data: {'text': 'hello world'}, success: function (msg) { $("button").html(msg); }
}); }); </script> </body> </html>
|
服务器端 www.server.com/server.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| //允许所有域名获取数据 <?php $text = $_POST['text']; //允许所有的域名 header('content-type:application:json;charset=utf8'); header('Access-Control-Allow-Origin:*'); header('Access-Control-Allow-Methods:POST,GET'); header('Access-Control-Allow-Headers:x-requested-with,content-type'); echo json_encode($text); ?>
//允许制定域名获取数据 <?php $text = $_POST['text']; header('content-type:application:json;charset=utf8'); $origin = isset($_SERVER['HTTP_ORIGIN']) ? $_SERVER['HTTP_ORIGIN'] : ''; //允许指定域名 $allow_origin = [ 'http://www.client.com', 'http://www.client2.com' ]; if (in_array($origin, $allow_origin)) { header('Access-Control-Allow-Origin:' . $origin); header('Access-Control-Allow-Methods:POST,GET'); header('Access-Control-Allow-Headers:x-requested-with,content-type'); } echo json_encode($text); ?>
|
这样,理论上就可以解决跨域问题:
Solution 2:代理模式
解决思路:
例如 www.client.com/client.html 需要调用 www.server.com/server.php ,可以写一个接口 www.client.com/server.php ,由这个接口在后端去调用 www.server.com/server.php 并拿到返回值,然后再返回给index.html,这就是一个代理的模式.相当于绕过了浏览器端,自然就不存在跨域问题.
Solution 3:使用JSONP
使用之前,建议去看下我的另一篇文章Json和JsonP,然后再过来实践;
还是直接上代码:
客户端 www.client.com/client.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| <!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html;charset=utf-8"> <title> 跨域测试 </title> <script src="//code.jquery.com/jquery-1.11.3.min.js"></script> </head>
<body> <button id="clickMe" style="width:100px">click get jsonP</button> <script type="text/javascript"> $("#clickMe").click(function () { $.ajax({ url: "http://www.server.com/jsonP.json", type: "post", dataType: "jsonP", data: {'text': 'hello world'}, jsonpCallback: 'returnData', //可自定义 函数名 success: function (msg) { alert(msg.text); }, error: function (XMLHttpRequest, textStatus, errorThrown) { alert(XMLHttpRequest.status); alert(XMLHttpRequest.readyState); alert(textStatus); } }); }); </script> </body> </html>
|
服务器端 www.server.com/jsonP.json
1
| returnData({"text":"hello jsonP"});
|
同样的也可以跨域获取数据
客户端 www.client.com/client.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <iframe style="display: none" src="http://www.server.com/server.html" name="postIframe" onload="messageLoad()"></iframe> <script> function messageLoad() { var url = "http://www.server.com"; window.postIframe.postMessage("给我tsort的信息", url); //发送数据 } window.onmessage = function (e) { e = e || event; console.log(e.data); //接收b返回的数据,在控制台有两次输出 } </script> </body> </html>
|
服务器端 www.server.com/server.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <script> window.onmessage = function(e){ e = e || event; alert(e.data); //立即弹出a发送过来的数据 e.source.postMessage("好的,请稍等三秒!",e.origin); //立即回复a
var postData = {name:"tsrot",age:24}; var strData = JSON.stringify(postData); //json对象转化为字符串 setTimeout(function(){ e.source.postMessage(strData,e.origin); },3000); //3秒后向a发送数据 } </script> </body> </html>
|