前端跨域问题解决方法

1.什么是跨域及产生原因

跨域(Cross-origin)是指a页面想获取b页面资源,如果a、b页面的协议、域名、端口、子域名不同,或是a页面为ip地址,b页面为域名地址,所进行的访问行动都是跨域的,而浏览器为了安全问题一般都限制了跨域访问,也就是不允许跨域请求资源。

跨域情况如下:

url 说明 是否跨域
http://www.cnblogs.com/a.js
http://www.a.com/b.js
不同域名
http://www.a.com/lab/a.js
http://www.a.com/script/b.js
同一域名下不同文件夹
http://www.a.com:8000/a.js
http://www.a.com/b.js
同一域名,不同端口
http://www.a.com/a.js
https://www.a.com/b.js
同一域名,不同协议
http://www.a.com/a.js
http://70.32.92.74/b.js
域名和域名对应ip
http://www.a.com/a.js
http://script.a.com/b.js
主域相同,子域不同 是(cookie不可访问)
http://www.a.com/a.js
http://a.com/b.js
同一域名,不同二级域名(同上)

2.跨域的常见解决方法

目前来讲没有不依靠服务器端来跨域请求资源的技术

  1.jsonp 需要目标服务器配合一个callback函数。

什么是jsonp呢?可以从jsonp的来源来讲,我们知道Ajax直接请求普通文件不管是静态页面、动态页面、web服务只要跨域都存在无权限访问的问题,但是我们web页面上调用js文件时呢则不受是否跨域的影响(不仅如此,我们还发现凡是拥有‘src’属性的标签都用跨域的能力,比如<script>,<img>,<iframe>),于是如果想通过纯web端跨域访问数据只有一种可能,那就是在远程服务器上设法把数据装进js格式的文件里,供客户端调用,刚好有一种叫json的数据格式可以描述复杂数据,而json呢也是被js原生支持的,所以我们可以在客户端通过与调用脚本一样的方式,来调用跨域服务器上动态生成的js格式文件(一般以json为后缀)。客户端在对json文件成功调用后,也就获得了自己想要的数据,剩下的就是按照自己的需求进行处理和展现了,这种方式看起来非常像AJAX,但其实并不一样。为便于客户端使用数据,逐渐形成一种非正式传输协议,人们把它称作jsonp,该协议的一个要点就是允许用户传递一个callback参数给服务器,然后服务端返回数据时会将这个callback参数作为函数名来包裹住json数据,这样客户端就可以随意定制自己的函数来自动处理返回的数据了。

jsonp的客户端具体实现:

<!DOCTYPE>
<html>
<head>
    <title></title>
    <script type="text/javascript">
    // 得到航班信息查询结果后的回调函数
    var flightHandler = function(data){
        alert('你查询的航班结果是:票价 ' + data.price + ' 元,' + '余票 ' + data.tickets + ' 张。');
    };
    // 提供jsonp服务的url地址(不管是什么类型的地址,最终生成的返回值都是一段javascript代码)
    var url = "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998&callback=flightHandler";
    // 创建script标签,设置其属性
    var script = document.createElement('script');
    script.setAttribute('src', url);
    // 把script标签加入head,此时调用开始
    document.getElementsByTagName('head')[0].appendChild(script); 
    </script>
</head>
<body>
 
</body>
</html>

服务端数据

flightHandler({
    "code": "CA1998",
    "price": 1780,
    "tickets": 5
});

虽然ajax和jsonp的调用方式看起来很像,目的也一样,都是请求一个url,然后把服务器返回的数据进行处理,ajax和jsonp其实本质上是不同的东西。ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加

  2.window.name+iframe 需要目标服务器响应window.name。

  3.window.location.hash+iframe 同样需要目标服务器作处理。

  4.html5的 window.postMessage 这个也是需要目标服务器或者说是目标页面写一个postMessage,主要侧重于前端通讯。

  5.跨域资源共享CORS

CORS(Cross-Origin Resource Sharing),  通过在服务器端设置:Access-Control-Allow-Origin响应头,允许浏览器发起跨域请求,例如,跨域XMLHttpRequest, Fetch请求。

Access-Control-Allow-Origin的值为发起跨域请求的那个域名,表示允许这个域名的网页访问当前资源。服务器端可以通过请求头的Origin字段,来判断某个请求是否跨域请求。

下面是由于端口号不同导致的无法请求资源的错误提示信息

 服务器端如果没有设置CORS,普通的跨域<script>标签,将只向window.onerror反馈尽量少的内容。

window.onerror = (...args) => console.log(args);  // ["Script error.", "", 0, 0, null]

 给<script>标签添加crossorigin属性,并在服务器端设置Access-Control-Allow-Origin响应头,允许脚本被跨域访问,就可以在window.onerror中获取更详细的日志信息。

[
    "Uncaught ReferenceError: a is not defined", 
    "http://127.0.0.1:8081/index.js", 
    1, 
    1, 
    ReferenceError: a is not defined
        at http://127.0.0.1:8081/index.js:1:1
]

 注:普通<script>标签是可以加载跨域脚本的,但如果给跨域<script>标签添加了crossorigin属性,(且服务器端没有设置Access-Control-Allow-Origin响应头),就会出现以下错误,

Access to Script at 'http://127.0.0.1:8081/index.js' from origin 'http://127.0.0.1:8080' has been blocked by CORS policy: 
No 'Access-Control-Allow-Origin' header is present on the requested resource. 
Origin 'http://127.0.0.1:8080' is therefore not allowed access.

 crossorigin 属性不止可以用于<script>标签,还可以用与<img><video>等标签,通常用设置 crossorigin 来获取异步加载的脚本执行时的详细错误信息。
用于配置 CORS 的请求数据,见下表,

Keyword State Request Mode Credentials Mode
the attribute is omitted  No CORS "no-cors" "omit"
"" Anonymous "cors" "same-origin"
"anonymous" Anonymous  "cors" "same-origin"
"use-credentials" Use Credentials "cors" "include"

 

不同的crossorigin值,指定了不同的Request Mode和Credentials Mode。

  • anonymous(默认) 在加载此脚本资源时不会带上用户的 Cookies;
  • use-credentials 在加载此脚本资源时会带上用户的 Cookies。

  6.nginx反向代理 这个方法一般很少有人提及,但是他可以不用目标服务器配合,不过需要你搭建一个中转nginx服务器,用于转发请求。

http://www.cnblogs.com/gabrielchen/p/5066120.html

 

posted @ 2015-12-22 21:43  pei~乐悠悠  阅读(1086)  评论(0编辑  收藏  举报