跨域了解和资料学习

什么是跨域?

跨域是指一个域下的文档或脚本在浏览器端试图去请求另一个域下的资源

广义跨域:
1.) 资源跳转: A链接、重定向、表单提交
2.) 资源嵌入: <link><script><img><frame>等dom标签,还有样式中background:url()、@font-face()等文件外链
3.) 脚本请求: js发起的ajax请求、dom和js对象的跨域操作等

工作中遇到的。--狭义 ----是由浏览器同源策略限制的一类请求场景。

什么是同源策略?
是一种约定
所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。
一个网站的网址组成包括协议名,子域名,主域名,端口号。比如https://www.github.com/80

同源策略限制一下几种行为
1.) Cookie、LocalStorage 和 IndexDB 无法读取
2.) DOM 和 Js对象无法获得
3.) AJAX 请求不能发送

跨域解决方案

1、 通过jsonp跨域

$.ajax({  
        type : "get",  
        async:false,  
        url : "http://XXX/base/json.do?sid=1494&busiId=101",  
        dataType : "jsonp",//数据类型为jsonp  
        jsonp: "jsonpCallback",//服务端用于接收callback调用的function名的参数  
        success : function(data){ 
           console.log(data)
        },  
        error:function(error){  
           console.log(error); 
        }
    }); 

JSON数据是一种能很方便通过JavaScript解析的结构化数据。如果获取的数据文件存放在远程服务器上(域名不同,也就是跨域获取数据),则需要使用jsonp类型。使用这种类型的话,会创建一个查询字符串参数 callback=? ,这个参数会加在请求的URL后面。服务器端应当在JSON数据前加上回调函数名,以便完成一个有效的JSONP请求。如果要指定回调函数的参数名来取代默认的callback,可以通过设置$.ajax()的jsonp参数。

JSONP和JSON好像啊,他们之间有什么联系吗?

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。对于JSON大家应该是很了解了吧,不是很清楚的朋友可以去json.org上了解下,简单易懂。

JSONP是JSON with Padding的略称。它是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问(这仅仅是JSONP简单的实现形式)。

"jsonp": JSONP 格式。使用 JSONP 形式调用函数时,如 "myurl?callback=?" jQuery 将自动替换 ? 为正确的函数名,以执行回调函数。

2、 document.domain + iframe跨域

前提条件:
这两个域名必须属于同一个一级域名!而且所用的协议,端口都要一致,否则无法利用document.domain进行跨域。
js出于对浏览器安全性的考虑,禁止两个或者多个不同域的页面进行互相操作。
而相同域的页面在相互操作的时候不会有任何问题。

两个子域名下:
a.baidu.com(a.html)
b.baidu.com(b.html)
a.baidu.com里的一个网页(a.html)引入了b.baidu.com里的一个网页(b.html)

这时a.html里同样是不能操作b.html里面的内容的。
因为document.domain不一样,一个是a.baidu.com,另一个是b.baidu.com。
这时我们就可以通过Javascript,将两个页面的domain改成一样的,
需要在a.html里与b.html里都加入:

document.domain = “baidu.com”;

这样这两个页面就可以互相操作了。也就是实现了同一一级域名之间的"跨域"。

a.baidu.com下的a.html页面:

<script>
    document.domain = 'baidu.com';
    var ifr = document.createElement('iframe');
    ifr.src = 'b.baidu.com/b.html';
    ifr.style.display = 'none';
    document.body.appendChild(ifr);
    ifr.onload = function(){
        var doc = ifr.contentDocument || ifr.contentWindow.document;
        // 这里可以操作b.baidu.com下的b.html页面
        var oUl = doc.getElementById('ul1');
        alert(oUl.innerHTML);
        ifr.onload = null;
    };
</script>

b.baidu.com下的b.html页面:

<ul id="ul1">我是b.baidu.com中的ul</ul>
<script>
    document.domain = 'baidu.com';
</script>

3、 location.hash + iframe

a.baidu.com#some这个#some就是hash,并不会导致页面刷新,可以通过hash传递数据,但是容量有限
a域名下的a.html要和b域名下的b.html传递消息,首先a.html要创建一个隐藏的iframe,,iframe的src指向b域名下b.html(由于两个页面不在同一个域下IE、Chrome不允许修改parent.location.hash的值,所以要借助于a.com域名下的一个代理iframe;Firefox可以修改)
当然这样做也存在很多缺点,诸如数据直接暴露在了url中,数据容量和类型都有限

4、 window.name + iframe跨域

同2,3类似 window.name是窗口名称

5、 postMessage跨域

html5引入的postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递。
postMessage(data,origin)方法接受两个参数

data:html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以传参时最好用JSON.stringify()序列化。

origin: 协议+主机+端口号,也可以设置为"*",表示可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。
(pc貌似出现过类似的问题)

10.73.154.72页面t_hotnotes_list.html插入如下代码

<iframe id="iframe" src="http://10.73.154.73:8088/rbc/t/search_role.html" style="display:none;"></iframe>
    <script>       
        var iframe = document.getElementById('iframe');
        iframe.onload = function() {
            var data = {
                name: 'aym',
                type:'wuhan'
            };
            // 向domain2传送跨域数据
            iframe.contentWindow.postMessage(JSON.stringify(data), 'http://10.73.154.73:8088');
        };

        // 接受domain2返回数据,这边给延迟的原因,因为同步传输时,页面不一定立马拿到数据,所以给延迟
        setTimeout(function(){
            window.addEventListener('message', function(e) {
                alert('data from domain2 sss ---> ' + e.data);
            }, false);
        },10)
    </script>

10.73.154.73页面search_role.html插入如下代码:

<script>
        // 接收domain1的数据
        window.addEventListener('message', function(e) {
            console.log(e.data);

            var data = JSON.parse(e.data);
            if (data) {
                data.number = 16;
                data.age = 89;
                data.icon = 'sfafdafdafasdf';

                // 处理后再发回domain1
                window.parent.postMessage(JSON.stringify(data), 'http://10.73.154.72:8088');
            }
        }, false);
    </script>

6、 vue解决跨域

利用node + webpack + webpack-dev-server代理接口跨域
跨域是浏览器禁止的,服务端并不禁止跨域 
所以浏览器可以发给自己的服务端然后,由自己的服务端再转发给要跨域的服务端,做一层代理
vue-cli的proxyTable用的是http-proxy-middleware中间件
create-react-app用的是webpack-dev-server内部也是用的http-proxy-middleware
http-proxy-middleware内部用的http-proxy

var express = require('express');
var proxy = require('http-proxy-middleware');
 
var app = express();

app.use('/api', proxy({target: 'http://10.119.168.87:4000', changeOrigin: true}));
app.listen(3000);

我们利用express在3000端口启动了一个小型的服务器,
利用了
app.use('/api', proxy({target: 'http://10.119.168.87:4000/', changeOrigin: true}))这句话,
使发到3000端口的/api请求转发到了4000端口。
即请求http://localhost:3000/api相当于请求http://10.119.168.87:4000/api。

1、 跨域资源共享(CORS)---延后
2、 nginx代理跨域 --- 延后
3、 nodejs中间件代理跨域 ---延后

普通跨域请求:只服务端设置Access-Control-Allow-Origin即可
前端无须设置,若要带cookie请求:前后端都需要设置。

需注意的是:由于同源策略的限制
所读取的cookie为跨域请求接口所在域的cookie
而非当前页。如果想实现当前页cookie的写入
可以加入nginx反向代理中设置proxy_cookie_domain 和 
NodeJs中间件代理中cookieDomainRewrite参数的设置。

目前,所有浏览器都支持该功能(IE8+:IE8/9需要使用XDomainRequest对象来支持CORS)),CORS也已经成为主流的跨域解决方案。

https://www.cnblogs.com/zhangruiqi/p/7880642.html(jsonp和jsoncallback的使用)

http://www.ruanyifeng.com/blog/2016/04/cors.html(跨域资源共享 CORS 详解)

http://www.nginx.cn/doc/(中文文档)

http://www.phpvar.com/archives/3212.html(HTML5 Access-Control-Allow-Origin解决跨域问题)

https://blog.csdn.net/shaotaiban1097/article/details/90727229(node.js跨域请求配置)

https://blog.csdn.net/sps900608/article/details/79599121(vue解决跨域)

posted @ 2022-09-29 14:27  与君别  阅读(24)  评论(0编辑  收藏  举报