杂谈——关于“域”和“跨域”那些事

注:本文主要用于自主总结,后期会更新。如果要最全面的,可以参考大神的文章正确面对跨域、别慌

好啦,进入正题。

今天我们来了解一下“跨域”。

究竟什么是跨域呢?首先我们得先了解一下什么是域。

一、域是什么?

在今天很多人都有意识或无意识的跟域这个东西打过交道。如果你在公司里使用电脑,并且你的电脑接入了公司的局域网,那你的电脑很可能就在一个域中。

如何查看你的电脑是否连接到一个域中,以Windows为例,右击我的电脑 –>属性,可以看到,我现在使用的这台电脑就加入了一个域。 域已经成为绝大多数公司组织、连接电脑的一种方式。

那么我们究竟为什么要使用域?它能给我们带来什么好处呢?

假设你是公司的系统管理员,你们公司有一千台电脑。如果你要为每台电脑设置登录帐户,设置权限(比如是否允许登录帐户安装软件),那你要分别坐在这一千台电脑前工作。如果你要做一些改变,你也要分别在这一千台电脑上修改。相信没有哪个管理员想要用这种不吃不喝不睡觉的方式来工作,所以就应运而生了域的概念。

 还以Windows为例,在微软的世界中,一个域是由一个或多个域控制器(domain controller)来控制的(其实域控制器并不神秘,无非就是装了一些特别软件的电脑)。其他的电脑加入该域,就要接受域控制器的控制。域控制器中有两个重要的表,一个是加入该域的电脑的列表,另一个表用来保存叫做活动目录(Active Directory)的东西。活动目录就是你登录公司网络的帐户。活动目录中存储着你的权限。你在某台电脑上登录,你键入用户名和密码,你的电脑首先要把你的登录信息发送到域控制器,域控制器首先核实你的登录信息是否正确,然后把一个叫access key的东西返还给你登录的电脑。这个access key中就包含着你的权限,由它来决定你是否可以安装软件,或者使用打印机等等。

有了域以后,作为管理员,你就可以坐在一台电脑前,登录到域控制器上,对一切权限进行控制,而不用跑到每台电脑前进行设置了。工作效率提高了很多,但是还不够。假设公司有一千名员工,你是否要在域控制器中对这一千个人分别进行权限的设置呢?这听起来也是一件很麻烦的事。其实很多员工的权限都是相同的,那我们可不可以对这些相同的权限只设置一次,然后将该权限分配给相关的员工呢?

答案就是使用分组(Group)。比如在学校里,我们设置学生组和教师组。在某台电脑上我们设置一个共享文件夹,学生组的权限是不可访问,而教师组可以对该文件夹进行访问。我们将不同的用户放入不同的分组里,然后对组进行权限设置,这样就免去了我们要对每个用户进行设置的麻烦。比组更大的单位是组织单位(Organization Unit),一个组织单位可以包含用户,组,资源(电脑,打印机等),还可以包含其他组织单位。

举个简单的例子,有一个商场中的电脑加入了该商场的域,但是该电脑放置在公共场合,有很大的风险,所以我们可以将该电脑放置在一个单独的组织单位中,然后对该组织单位进行权限设置,比如不论谁在该组织单位中登录,都不可以修改他的密码。在很多的实际情况中,一个公司又有下面的子公司,所以就造成母公司有一个域,而子公司也有一个单独的域。母公司的域与子公司的域如何联系起来呢?我们可以在它们之间建立一种叫信任(Trust)的关系。如果母公司的帐户想要能够登录到子公司的域中,子公司的域就要对母公司的域建立信任关系。当母公司域的帐户想要登录到子公司域中时,子公司域由于信任母公司的域,所以它会听从从母公司域的域控制器返回的access key。反过来,由于母公司的域没有建立对子公司的信任,所以如果子公司的帐户想要登录到母公司的域中是不可能的。

注:虽然我们上面的例子都是Windows的域,但域这个概念绝不是微软独创的。你也可以在Linux中使用一个叫Samba的软件来创建域。如果你要用Windows搭建一个域环境的话,要注意两点:

(1) 加入域不能使用Home版的Windows操作系统(顾名思义它是给你在家用的,而你家里是不用搭建域的)。

(2) 域控制器不能使用web edition server,因为它没有安装活动目录。 在现实环境中,有很多公司在域中使用多个域控制器,因为如果只使用一个域控制器的话,一旦域控制器不能正常工作,整个域就会瘫痪。在Samba中,Linux使用两个域控制器,一个是主域控制器,一个是备份域控制器。一旦主域控制器发生故障,备份域控制器就开始工作,直到主域控制器恢复正常。备份域控制器就是一个主域控制器的拷贝,但是它的数据都是只读的,也就是说管理员不能在备份域控制器上修改权限。

二、什么是域名

域,就像是一座城,那有了城,这座城当然就得有名字啦,我们总不能一直叫“那座城”吧。

域名呢,就是你在这个体系中的名称或地址。

可能有人对于域名有过了解,我们先回顾一下域名地址的组成:
http:// (协议号)
www (子域名)
google (主域名)
8080 (端口号)
script/jquery.js (请求的地址)
* 当协议、子域名、主域名、端口号都相同时,属于同一个“域”。

三、什么是跨域

从上文我们可以知道,一个域名包含协议号、子域名、主域名、端口号以及请求的地址。当协议、子域名、主域名、端口号都相同时,属于同一个“域”。

既然有同“域”,那当然也有跨域了。那什么叫跨域呢?

当协议、子域名、主域名、端口号中任意一各不相同时,都算不同的“域”。 不同的域之间相互请求资源,就叫“跨域”。

也许光说的话大家不好理解,那么正好拾人牙慧,给大家举些例子。

http://www.111.com/index.html 调用 http://www.111.com/server.php (非跨域)

http://www.111.com/index.html 调用 http://www.222.com/server.php (主域名不同:123/456,跨域)

http://abc.111.com/index.html 调用 http://def.111.com/server.php (子域名不同:abc/def,跨域)

http://www.111.com:8080/index.html 调用 http://www.111.com:8081/server.php (端口不同:8080/8081,跨域)

http://www.111.com/index.html 调用 https://www.111.com/server.php (协议不同:http/https,跨域)

需要注意一点:localhost和127.0.0.1虽然都指向本机,但也属于跨域。

看完上面的例子,大家想必就明白什么叫跨域了。

四、如何跨域?

跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实施的安全限制。

同源策略限制了一下行为:

  • Cookie、LocalStorage 和 IndexDB 无法读取
  • DOM 和 JS 对象无法获取
  • Ajax请求发送不出去

浏览器执行javascript脚本时,会检查这个脚本属于哪个页面,如果不是同源页面,就不会被执行。

那我要跨域访问的话,又该如何呢?

解决办法:

1、JSONP:

jsonp 全称是JSON with Padding,是为了解决跨域请求资源而产生的解决方案,是一种依靠开发人员创造出的一种非官方跨域数据交互协议。

一个是描述信息的格式,一个是信息传递双方约定的方法。

jsonp的产生:

1.AJAX直接请求普通文件存在跨域无权限访问的问题,不管是静态页面也好.

2.不过我们在调用js文件的时候又不受跨域影响,比如引入jquery框架的,或者是调用相片的时候

3.凡是拥有scr这个属性的标签都可以跨域例如<script><img><iframe>

4.如果想通过纯web端跨域访问数据只有一种可能,那就是把远程服务器上的数据装进js格式的文件里.

5.而json又是一个轻量级的数据格式,还被js原生支持

6.为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP,该协议的一个要点就是允许用户传递一个callback 参数给服务端,

要注意JSONP只支持GET请求,不支持POST请求。

demo1:基于script标签实现跨域

举个例子:我在http://study.cn/json/jsonp/jsonp_2.html下请求一个远程的js文件


<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

<script type="text/javascript">
    var message = function(data) {
        alert(data[1].title);
    };
</script>

<script type="text/javascript" src="http://web.cn/js/message.js"></script>
</head>
<body>
<div id='testdiv'></div>
</body>
</html>

远程的message.js文件是

message([
     {"id":"1", "title":"天津新闻联播,雷人搞笑的男主持人"},
     {"id":"2", "title":"楼市告别富得流油 专家:房价下跌是大概率事件"},
     {"id":"3", "title":"法国人关注时事 八成年轻人每天阅读新闻"},
     {"id":"4", "title":"新闻中的历史,历史中的新闻"},
     {"id":"5", "title":"东阳新闻20140222"},
     {"id":"6", "title":"23个职能部门要增加新闻发布频次"},
     {"id":"7", "title":"《贵州新闻联播》 中国美丽乡村"},
     {"id":"8", "title":"朝韩离散家属团聚首轮活动结束"},
     {"id":"9", "title":"索契冬奥会一天曝出两例兴奋剂事件"},
     {"id":"10", "title":"今天中国多地仍将出现中度霾"}
 ]);

这个时候我们得到的相应头是:

这样就实现跨域成功了,因为服务端返回数据时会将这个callback参数(message)作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。

demo2: 基于script标签实现跨域

让远程js知道它应该调用的本地函数叫什么名字,只要服务端提供的js脚本是动态生成的就好了,这样前台只需要传一个callback参数过去告诉服务端,我需要XXX代码,于是服务端就会得到相应了.

例如 在http://study.cn/json/jsonp/jsonp_3.html页面请求 http://192.168.31.137/train/test/jsonpthree

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

<script type="text/javascript">
    var messagetow = function(data){
        alert(data);
    };
    var url = "http://192.168.31.137/train/test/jsonpthree?callback=messagetow";
    var script = document.createElement('script'); 
    script.setAttribute('src', url); 
    document.getElementsByTagName('head')[0].appendChild(script);
</script>
</head>
<body>
</body>
</html>

得到的响应头是:

demo3:  基于jquery跨域

那么如何用jquery来实现我们的跨域呢???jquery已经把跨域封装到ajax上了,而且封装得非常的好,使用起来也特别方便

如果是一般的ajax请求:

$.ajax({
        url:'http://192.168.31.137/train/test/testjsonp',
        type : 'get',
        dataType : 'text',
        success:function(data){
            alert(data);
        },
        error:function(data){
            alert(2);
        }        
    });​​​​​​​

那么在浏览器中会报错:

jsonp形式的ajax请求:并且通过get请求的方式传入参数,注意:跨域请求是只能是get请求不能使用post请求

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="./js/jquery.js"></script>
<script type="text/javascript">
$(document).ready(function(){
    var name = 'chenshishuo';
    var sex = 'man';
    var address = 'shenzhen';
    var looks = 'handsome ';
     $.ajax({
         type : 'get',
         url:'http://192.168.31.137/train/test/testjsonp',
        data : {
            name : name,
            sex : sex,
            address : address,
            looks : looks,
        },
        cache :false,
        jsonp: "callback",
        jsonpCallback:"success",
        dataType : 'jsonp',
        success:function(data){
            alert(data);
        },
        error:function(data){
            alert('error');
        }        
    });
});
</script>
</head>
<body>
<input id='inputtest' value='546' name='inputtest'>
<div id='testdiv'></div>
</body>
</html>
jsonp 传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(默认为:callback)
jsonpCallback 自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名

看看请求头和相应头吧

请求头:jquery会自动带入callback参数,当服务端获取到这个参数后,返回回来.(响应头)

2、代理

例如www.123.com/index.html需要调用www.456.com/server.php,可以写一个接口www.123.com/server.php,由这个接口在后端去调用www.456.com/server.php并拿到返回值,然后再返回给index.html,这就是一个代理的模式。相当于绕过了浏览器端,自然就不存在跨域问题。

用的大多数的方式就是用ifram代理。

如果你想在http://a.study.cn/a.html页面中通过ajax直接请求页面http://b.study.cn/b.html,即使你设置了相同的document.domain也还是不行的.

所以修改document.domain的方法只适用于不同子域的框架(父类与子类)间的交互。

如果想通过使用ajax的方法去与不同子域间的数据交互或者是js调用,只有两种方法,一种是使用jsonp的方法外,还有一种是使用iframe来做一个代理。

原理就是让这个 iframe载入一个与你想要通过ajax获取数据的目标页面处在相同的域的页面,所以这个iframe中的页面是可以正常使用ajax去获取你要的数据 的,

然后就是通过我们刚刚讲得修改document.domain的方法,让我们能通过js完全控制这个iframe,这样我们就可以让iframe去发 送ajax请求,然后收到的数据我们也可以获得了。

下面是一个例子:

demo4: 通过iframe来跨子域

http://a.study.cn/a.html 请求 http://b.study.cn/b.html

在a.html:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
        <script type="text/javascript">
            document.domain = 'study.cn';
            function test() {
                alert(document.getElementById('a').contentWindow);
            }
        </script>
</head>
<body>
    <iframe id='a' src='http://b.study.cn/b.html' onload='test()'>
</body>
</html>

 在b.html:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

<script type="text/javascript">
document.domain = 'study.cn';
</script>
</head>
<body>
    我是b.study.cn的body
</body>
</html>

 运行效果截图:

我们就可以通过js访问到iframe中的各种属性和对象了

这里需要注意的是:

基于iframe实现的跨域要求两个域具有aa.xx.com,bb.xx.com 这种特点,

也就是两个页面必须属于一个基础域(例如都是xxx.com),使用同一协议和同一端口,这样在两个页面中同时添加document.domain,就可以实现父页面调用子页面的函数

要点就是 :通过修改document.domain来跨子域

3、PHP端修改header(XHR2方式)

在php接口脚本中加入以下两句即可:

header('Access-Control-Allow-Origin:*');//允许所有来源访问

header('Access-Control-Allow-Method:POST,GET');//允许访问的方式
 

好啦,以上就是关于域的一些总结。大家如果对于上文总结的内容有自己的看法,欢迎留言评论,我们一起交流交流呀~~

本文参考文章:

https://www.cnblogs.com/chenshishuo/p/4919224.html?tdsourcetag=s_pcqq_aiomsg

https://blog.csdn.net/lambert310/article/details/51683775?tdsourcetag=s_pcqq_aiomsg

猜你喜欢

转载自blog.csdn.net/Searchin_R/article/details/84236340