文章目录
一、结论
- 域、跨域都和IP关系不大,和域名有关。
- 域名并不是真正的域名
- 跨域严格上说是跨源
二、什么是域 Domain
百度百科的解释
域是一个网络应用的范围,在这个范围内的用户有一定的访问权限网络内用户或者主机,而不在域中的用户会受到域权限的控制而不能访问一些东西,也就是提升了局域网安全性的一个措施。
简单说,是一种安全策略,将计算机分组,同域的计算机,可以有一定的访问权限。不同域的计算机,会受到访问限制。
三、什么是域名
我们使用域名来代表(管理)ip地址,使用域名来划分域。
一开始只有ip地址,ip地址一串纯数字太难记,便设计了域名用来代表ip的这一串数字,方便识别与记忆。网络中有一系列叫做域名系统(DNS Domain Name System)的系统,里面记录有域名和ip的对应关系。通过域名访问某个站点时,会先经过域名系统,将域名解析成ip地址,再进行路由。
一个域名可以指向多个ip(负载均衡),不同的域名也可能指向同一个ip地址,属于多对多的关系,所以我们上面使用了代表和管理两个词。
1、如何划分域
ip用来路由,域名用来区分域。
在只有ip的时候,通过将ip划分到域(类似分组)的方式来划分域,现在windows操作系统里面仍然可以这样分。在有了域名之后,直接通过域名来划分域。
ip地址的数字主要用来路由,规定了每一位0-255,使用4位数字,以至于6位数字的组合来给每一台机器编号进行路由组网。而域名不需要用来路由,可以随意设置,有无限种可能,你起多长的名字都可以。
理论上只要一位就可以区分域名,但是为了管理方便,组织方便,仍然使用多级方式表示域名。这便是我们经常听到的顶级域名、一级域名、二级域名、三级域名之类的。
2、域名与hostname
还有个很有意思的事情是,事实我们把类似www.baidu.com叫做域名是不对的, 在维基百科的定义里,www不属于域名,加不加无所谓,baidu和com两个都算是域名(两个域名),com是一级域名,baidu是二级域名。www.baidu.com或者baidu.com合起来叫做hostname,但是后来我们都管整个hostname叫做域名。。。
四、跨域
按照上面的描述继续往下推,跨域就是两台域名不同的机器相互访问。
事实上并不是这样,跨域只是我们的叫法而已,我们在跨域的时候,打开F12,提示的是如下信息
这里面并没有出现任何域(domain)这样的字眼,而是Origin。跨域事实上应该叫做跨源Cross Origin。
1、什么是源,什么是跨源(域)
1)一次跨域过程的跟踪
我们先来追一下跨域的过程,来理解什么到底时候发生了跨域访问
我们再看上面图片的提示
- 我们从localhost:8080向localhost:8081去请求/test路径下的资源(不论是某个页面还是图片,ajax等)
- 我们事实上已经请求到了/test的资源。
- 8081服务把资源返回出来,交给浏览器,浏览器准备让localhost:8080去访问这个资源。
- 这个时候浏览器发现页面不同源,且返回资源的header中的Access-Control-Allow-Origin列表中并没有http://localhost:8080。于是对资源的继续访问被阻止了(been blocked),并抛出异常。
2、同源策略 (SOP Same Origin Policy)
关于同源策略,百度百科解释的稀烂,还那么短,有兴趣可以去查一查恶心一下自己。去维基或者MDN上看一下。
1)什么是同源策略
同源是指http请求发起侧和响应侧的协议、域名、端口全部相同(源 = 协议 + 域名 + 端口),其中任意一个不同就是跨源。
默认情况下,浏览器不允许跨源的访问。
2)为什么需要同源策略
主要是为了安全,保护网站内部资源,包括iframe,XMLHttpRequest(Ajax)、cookie、localstorage等。具体的展开我们在Web前端攻击篇再说。
关于为什么叫做跨域的猜测
那个时候可能并没有https,网站协议都是http,端口也是默认的80端口。这个时候,事实上导致“源”不同的,只有域名,跨域==跨源。
上面纯属个人猜测。
3)如何控制同源策略
浏览器自动检测是否同源,并严格执行同源策略。其中协议和端口无法控制,但是可以通过document.domain="xxx.xxx"来改变domain。这个改变是有规则的,考虑到www对理解的干扰,我们使用pan.baidu.com做例子,F12敲一下如下代码。
1. 提示说我们设置的"abc.com"不是“pan.baidu.com"的后缀。
2. 提示不能是一级域名。
也就是必须设置为当前网站的后缀,并且不能是一级域名,其实就是父域。
由于Cookie、Web Storage等都是基于domain(origin)收集的,修改domain行为也将会影响这些信息的收集。
a) CORS
浏览器严格执行同源策略,但是跨域是实际存在的业务需求。
怎么办?于是开了一个口子,叫做CORS(Cross-Origin Resource Sharing),跨源资源共享。
简单说,允许有条件的进行跨源访问,“”有条件“”具体表现为在header里面准备了三个Access-Control-Allow-XXX的属性,Access-Control-Allow-Origin,Access-Control-Allow-Methods,Access-Control-Allow-Headers,分别定义允许的请求来源、方法和头信息,只要请求同时满足这三个条件,则可以访问。
”简单请求“与”预检请求“
对于请求,按照请求方法和头信息,区分为”简单请求“与”预检请求“。
对于简单请求和预检请求具体是什么,详细内容自己到MDN上看。https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
MDN上的回答
”对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。"
“简单请求”,比如查询请求并不会对服务器造成什么副作用*,所以查询接口事实上会执行,在返回之后才判断是 否跨源,我们上面的例子,使用的就是简单的GET请求。
“预检请求”,比如增删改操作,或者一些搭配特殊头部信息的请求,可能会对服务器造成副作用,不可以先执行再判断,或者从效率上处理起来可能比较复杂。需要“预检”一下。
五、如何解决跨域
1、CORS
按照上面的描述,双方根据请求方法、资源做好约定,应答方在header中添加合适的Access-Control-Allow-XXX。这是最正统,最安全的解决跨域的手段。
2、JSONP
简单说,同源策略不限制src、href属性,我们可以随便创建一个带有src属性的元素,如script,img,或者link标签(href),将src/href指向要访问的地址,并带上对返回值进行处理的方法名,比如叫做myCallback。
这个地址发出去,就相当于一个get方法,目标服务器端执行了这个请求,将查询结果打成json,和方法名拼起来,变成myCallback({params}),请求端解析并执行这个方法,就达到了跨域请求的目的。
1)为什么叫做JSONP
Json With PaddingJson With Padding,返回一串Json,Padding(Prefix)了一个方法名。
2)CORS与JSONP对比
- JSONP是在CORS没有出来之前,绕过同源策略的一种方法。
- 而CORS是比较正统的解决方案。
- JSONP只支持GET,但是跨域请求一般也不太会用其它方式(因为往往都是跨域查询),GET足以应付大部分场景。如果需要对服务端资源进行操作,使用CORS。
- 如果需要兼容低版本的IE浏览器(IE8之前),需要使用JSONP。
- 从安全上讲,肯定是CORS更强。
3、PostMessage
H5的PostMessage,用于不同页面间的消息传递,同样也可以用于不同域的页面间的消息通信。可以先页面间通信,页面再与后端通信,也能达到跨域的目的。