前端跨域问题解决方法
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