前端跨域总结
一、通过document.domain + iframe实现
二、通过location.hash + iframe实现
三、通过window.name + iframe实现
四、通过HTML5的postMessage方法实现
上面三种方法都属于破解,HTML5为了解决这个问题,引入了一个全新的API:跨文档通信 API(Cross-document messaging)。
这个API为window对象新增了一个window.postMessage方法,允许跨窗口通信,不论这两个窗口是否同源。
举例来说,父窗口http://aaa.com向子窗口http://bbb.com发消息,调用postMessage方法就可以了。
var popup = window.open('http://bbb.com', 'title'); popup.postMessage('Hello World!', 'http://bbb.com');
postMessage方法的第一个参数是具体的信息内容,第二个参数是接收消息的窗口的源(origin),即"协议 + 域名 + 端口"。也可以设为*,表示不限制域名,向所有窗口发送。
子窗口向父窗口发送消息的写法类似。
window.opener.postMessage('Nice to see you', 'http://aaa.com');
父窗口和子窗口都可以通过message事件,监听对方的消息。
window.addEventListener('message', function(e) { console.log(e.data); },false);
message事件的事件对象event,提供以下三个属性。
event.source:发送消息的窗口
event.origin: 消息发向的网址
event.data: 消息内容
下面的例子是,子窗口通过event.source属性引用父窗口,然后发送消息。
window.addEventListener('message', receiveMessage); function receiveMessage(event) { event.source.postMessage('Nice to see you!', '*'); }
event.origin属性可以过滤不是发给本窗口的消息。
window.addEventListener('message', receiveMessage); function receiveMessage(event) { if (event.origin !== 'http://aaa.com') return; if (event.data === 'Hello World') { event.source.postMessage('Hello', event.origin); } else { console.log(event.data); } }
更多内容:http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html
五、通过jsonp实现
用JSONP获取的不是JSON数据,而是可以直接运行的JavaScript语句。
示例代码:
站点1,用来跨域请求的目标地址:http://localhost:8098/index.aspx
index.aspx.cs处理逻辑实现:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; namespace JSONPTest1 { public partial class index : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { //模拟数据 string jsonData="{\"IsSuccess\":true,\"Message\":\"承保成功\",\"result\":{\"TransRefGUID\":\"YSYJY201711211118578452\",\"Code\":\"22201711211106260661645\",\"Id\":\"368\"}}"; string callBack = Request.QueryString["callback"]; Response.Write(callBack + "(" + jsonData + ")"); Response.End(); } } }
站点2,发送跨域请求的地址:http://localhost:8199/index.aspx
这个页面中,有三种方式实现跨域访问:
1、通过script标签指向
<script type="text/javascript"> //通过script标签指向跨域地址时,需要执行的回调函数 function callbackProcess(data) { alert(JSON.stringify(data)); } </script> <!--通过script标签指向实现--> <script type="text/javascript" src="http://localhost:8098/index.aspx?callback=callbackProcess"></script>
2、通过jQuery的$.ajax方法
<script src="Scripts/jquery-1.8.2.min.js"></script> <script type="text/javascript"> //通过jQuery的全局方法$.ajax实现 var url = "http://localhost:8098/index.aspx"; $.ajax({ url: url, //这里虽设置为POST,但其实还是走的GET方式, //因为要请求的页面是用Request.QueryString["callback"]来接收参数的,如果POST有效的话,那请求就会报错了, //所以,正常执行就说明其实走的是GET。 type: "POST", dataType: "jsonp", //告诉服务器通过什么字段获取回调函数的名称 //如果设置的值与跨域请求的目标要接收的参数值不一致,则会报错,执行error jsonp: "callback", //声明本地回调函数的名称 jsonpCallback: "callbackProcess", success: function (data) { alert("ajax success callback: " + JSON.stringify(data)) }, error: function (jqXHR, textStatus, errorThrown) { alert(textStatus + ' ' + errorThrown); } }) </script>
3、通过jQuery的getJSON方法
<script src="Scripts/jquery-1.8.2.min.js"></script> <script type="text/javascript"> //通过jQuery的getJSON方法实现 var url = "http://localhost:8098/index.aspx"; $.getJSON(url+"?callback=?", {}, function (data,textStatus,jqXHR) { alert("data:" +JSON.stringify(data) + "\ntextStatus:" + textStatus); }) </script>
以上三种方式执行的结果大致是这样的:
jsonp缺点:
1、只能使用 GET 方法发起请求,这是由于 script 标签自身的限制决定的。
2、不能很好的发现错误,并进行处理。与 Ajax 对比,由于不是通过 XmlHttpRequest 进行传输,所以不能注册 success、 error 等事件监听函数。
(这点只针对第1种方式,2、3种可以监听success、 error)
六、通过CORS实现
CORS(Cross-Origin Resource Sharing)跨域资源共享。
IE10+
实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
服务器端对于CORS的支持,主要就是通过设置Access-Control-Allow-Origin来进行的。如果浏览器检测到相应的设置,就可以允许Ajax进行跨域的访问。
更多内容:http://www.cnblogs.com/zhaow/articles/9056089.html
CORS和JSONP对比
1、JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求。
2、使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理。
3、JSONP主要被老的浏览器支持,它们往往不支持CORS,而绝大多数现代浏览器都已经支持了CORS。
4、CORS与JSONP相比,无疑更为先进、方便和可靠。
七、 nginx代理跨域
八、 nodejs中间件代理跨域
九、 WebSocket协议跨域
参考资料:
http://www.ruanyifeng.com/blog/2016/04/cors.html
https://mp.weixin.qq.com/s/NOmsbKZsryTUONQj2gBFIA
http://mp.weixin.qq.com/s/CZgz0ya_RXhzDkEfv2_9iw
https://funteas.com/topic/59f6f16dadc582cf09ba794f
http://mp.weixin.qq.com/s/nZ26szrbNVQMwAo0rl3U9g
http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html