同源及跨域问题解决
1.同源策略
什么叫同源?
URL由协议、域名、端口和路径组成,如果两个URL的协议、域名和端口相同,则表示他们同源。相反,只要协议,域名,端口有任何一个的不同,就被当作是跨域。
浏览器采用同源策略,禁止页面加载或执行与自身来源不同的域的任何脚本。换句话说浏览器禁止的是来自不同源的"document"或脚本,对当前"document"读取或设置某些属性。
情景:
比如一个恶意网站的页面通过iframe嵌入了银行的登录页面(二者不同源),如果没有同源限制,恶意网页上的javascript脚本就可以在用户登录银行的时候获取用户名和密码。
浏览器中有哪些不受同源限制呢?
<script>、<img>、<iframe>、<link>这些包含 src 属性的标签可以加载跨域资源。但浏览器限制了JavaScript的权限使其不能读、写加载的内容。
2.跨域
跨域是指从一个域的网页去请求另一个域的资源。比如从http://www.baidu.com/ 页面去请求 http://www.google.com 的资源。
3.跨域技术-JSONP
JSONP是什么?
上面提到过包含src属性的<script>标签可以加载跨域资源。 JSONP就是利用<script>标签的跨域能力实现跨域数据的访问。
JSONP实现的原理
浏览器的同源策略把跨域请求都禁止了,但HTML的<script>标签是例外,可以突破同源策略从其他来源获取数据,通过<script>标签引入jsonp文件,然后通过一系列JS操作获取数据。
JSONP的缺点
JSONP只支持 GET 请求。
支持JSONP的不同技术
>>AngularJS
myUrl ="http://localhost:8090/api/test?callback=JSON_CALLBACK";
$http.jsonp(myUrl).success(
function(data){
alert(data);
}
);
1.angularJS中使用$http.jsonp函数
2.指定callback和回调函数名,函数名为JSON_CALLBACK时,会调用success回调函数,JSON_CALLBACK必须全为大写。
3.也可以指定其它回调函数,但必须是定义在window下的全局函数。
4.url中必须加上“callback”,其名称后台api提供而定,eg: http://localhost:8090/api/test?cb=JSON_CALLBACK
5.当callback为JSON_CALLBACK时,只会调用success,即使window中有JSON_CALLBACK函数,也不会调用该函数。
>>Ajax
emptymyUrl ="http://localhost:8090/api/test";
$.ajax({
type:"GET",
url:myUrl,
dataType:"jsonp",
jsonp:"callback",
jsonpCallback:"jsonpCallback",
success:function(data){
alert(data.msg);
}
});
function jsonpCallback(data){
alert(data);
}
JSONP 是通过动态添加<script>标签来调用服务器的脚本(<script>含有src属性,src属性没有跨域限制);而 Ajax 是通过 XHR(XmlHttpRequest)对象。两者并没有直接关系,以上只是Ajax封装JSONP的一种方式。
4.跨域技术-CORS (CrossOrigin Resources Sharing,跨源资源共享)
CORS是什么?
CORS,是 HTML5 的一项特性,它定义了一种浏览器和服务器交互的方式来确定是否允许跨域请求。
相对于 JSONP 这种解决方案来说,使用CORS,不需要要求服务器以指定格式返回数据(包装成JS脚本的格式:callback_func({ data }););CORS,只需要在服务器端做一些通用设置。
>>AngularJS
$http.get【实现跨域】
1, 在服务器端设置允许在其他域名下访问。Eg: response.setHeader("Access-Control-Allow-Origin", "http://www.123.com"); //允许www.123.com访问
2, AngularJS端使用$http.get()
$http.post【实现跨域】
1 在服务器端设置允许在其他域名下访问,及响应类型、响应头设置,eg:
response.setHeader("Access-Control-Allow-Origin", "*"); //允许哪些url可以跨域请求到本域
response.setHeader("Access-Control-Allow-Methods","POST"); //允许的请求方法
response.setHeader("Access-Control-Allow-Headers","x-requested-with,content-type"); //允许哪些请求头可以跨域
2 AngularJS端使用$http.post(),同时设置请求头信息,,eg:
$http.post('http://localhost:8080/api/Users',
{languageColumn:'name_eu'},
{'Content-Type':'application/x-www-form-urlencoded'})
.success(function(data){
$scope.users = data;
});