## 同源策略 **同源策略**是一个重要的安全策略,它用于限制一个origin的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。 如果两个 URL 的 protocol、port都相同的话,则这两个 URL 是同源。这个方案也被称为“协议/主机/端口元组”,或者直接是 “元组”。(“元组” 是指一组项目构成的整体,双重/三重/四重/五重/等的通用形式) 下表给出了与 URL `http://a.b.com/dir/page.html` 的源进行对比的示例: | URL | 结果 | 原因 | | --- | --- | --- | | http://a.b.com/dir2/other.html | 同源 | 只有路径不同 | | http://a.b.com/dir/inner/another.html| 同源 | 只有路径不同 | | https://a.b.com/secure.html | 失败 | 协议不同 | | http://a.b.com:81/dir/etc.html | 失败 | 端口不同 (http:// 默认端口是80) | | http://c.b.com/dir/other.html | 失败 | 主机不同 | --- ## 跨域请求 CORS即Cross Origin Resource Sharing(跨来源资源共享)。 所谓的跨域访问或者跨域请求,就是是指通过 js 在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据。只要协议、域名、端口有任何一个不同,都被当作是不同的域。 但不一定是浏览器限制了发起跨站请求,也可能是跨站请求可以正常发起,但是返回结果被浏览器拦截了。 ## 解决方案 ### jsonp **JSONP原理:动态创建script标签,使用script的src进行跨域** **具体步骤:** 1. 判断请求的与当前页面域是否同源,如果同源正常发送ajax,如果不同源,生成一个script标签 2. 生成一个随机的callback名字,并生成对应名字的方法。 3. 设置script的src为要请求的接口,将callback参数拼接在后面。 4. 后端接收到请求后,开始准备要返回的数据 5. 后端拼接数据,将要返回的数据用callback包裹起来,将内容返回。 6. 浏览区接收到内容那个,会当做js代码来执行。 7. 从而执行第二步生成的方法,这样就接收到后端返回给我们的对象。 由于jsonp的原理就是使用script标签进行跨域,而script都是使用get方式请求数据。所以jsonp跨域只能是get方法,即使你设置的post方法,jQuery也会自动转为get方法。 ### CROS 1. 跨域资源共享是一份浏览器技术的规范,以避开浏览器的同源策略,是 JSONP 模式的现代版。 2. CORS背后的思想,就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。 3. 与 JSONP 不同,CORS 除了 GET 要求方法以外也支持其他的 HTTP 要求。用 CORS 可以让前端工程师用一般的 XMLHttpRequest,这种方式的错误处理比 JSONP 要来的好;另一方面,JSONP 可以在不支持 CORS 的老旧浏览器上运作。现代的浏览器都支持 CORS。 具体做法:客户端不需要做什么,只需要在服务器端发送一个响应头即可:‘Access-Control-Allow-Origin’; 1. 如若允许所有域访问:Access-Control-Allow-Origin: \*;如:header("Access-Control-Allow-Origin: \*"); 2. 如若只允许指定域访问:Access-Control-Allow-Origin: 域名A;如:header("Access-Control-Allow-Origin: http://www.test2.com"); CORS分为两种 1、**简单请求** 2、**复杂请求** 1. 请求方法是以下三种方法之一: HEAD,GET,POST 2. HTTP请求头信息不超出以下几种字段: Accept Accept-Language Content-Language Last-Event-ID Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain **凡是不同时满足上面两个条件,就属于非简单请求。** 浏览器对这两种请求的处理,是不一样的。 Access-Control-Allow-Origin: http://www.test.com Access-Control-Max-Age: 3628800 Access-Control-Allow-methods: GET, PUT, DELETE, POST Access-Control-Allow-Header: content-type Access-Control-Allow-Credentail: true “Access-Control-Allow-Origin"表明它允许” http://www.test.com "发起跨域请求 "Access-Control-Max-Age"表明在3628800秒内,不需要再发送预检验请求,可以缓存该结果(上面的资料上我们知道CROS协议中,一个AJAX请求被分成了第一步的OPTION预检测请求和正式请求) "Access-Control-Allow-Methods"表明它允许GET、PUT、DELETE的外域请求 "Access-Control-Allow-Headers"表明它允许跨域请求包含content-type头 "Access-Control-Allow-Credentials"表明它允许cookies --- **复杂请求**表面上看起来和简单请求使用上差不多,但实际上浏览器发送了不止一个请求。其中最先发送的是一种"预请求",此时作为服务端,也需要返回"预回应"作为响应。预请求实际上是对服务端的一种权限请求,只有当预请求成功返回,实际请求才开始执行。 预请求以OPTIONS形式发送,当中同样包含域,并且还包含了两项CORS特有的内容: > Access-Control-Request-Method – 该项内容是实际请求的种类,可以是GET、POST之类的简单请求,也可以是PUT、DELETE等等。 > Access-Control-Request-Headers – 该项是一个以逗号分隔的列表,当中是复杂请求所使用的头部。 显而易见,这个预请求实际上就是在为之后的实际请求发送一个权限请求,在预请求回应返回的内容当中,服务端应当对这两项进行回复,以让浏览器确定请求是否能够成功完成。 > Access-Control-Allow-Origin(必含) – 和简单请求一样的,必须包含一个域。 > Access-Control-Allow-Methods(必含) – 这是对预请求当中Access-Control-Request-Method的回复,这一回复将是一个以逗号分隔的列表。尽管客户端或许只请求某一方法,但服务端仍然可以返回所有允许的方法,以便客户端将其缓存。 > Access-Control-Allow-Headers(当预请求中包含Access-Control-Request-Headers时必须包含) – 这是对预请求当中Access-Control-Request-Headers的回复,和上面一样是以逗号分隔的列表,可以返回所有支持的头部。这里在实际使用中有遇到,所有支持的头部一时可能不能完全写出来,而又不想在这一层做过多的判断,没关系,事实上通过request的header可以直接取到Access-Control-Request-Headers,直接把对应的value设置到Access-Control-Allow-Headers即可。 一旦预回应如期而至,所请求的权限也都已满足,则实际请求开始发送。