因为 Javascript 同源策略的存在使得一个源中加载来自其它源中资源的行为受到了限制。即会出现跨域请求禁止。html
通俗一点说就是若是存在协议、域名、端口或者子域名不一样服务端,或一者为IP地址,一者为域名地址(在跨域问题上,域仅仅是经过“ url的首部 ”来识别而不会去尝试判断相同的IP地址对应着两个域或者两个域是否同属同一个IP),之中任意服务端旗下的客户端发起请求其它服务端资源的访问行动都是跨域的,而浏览器为了安全问题通常都限制了跨域访问,也就是不容许跨域请求资源。前端
但不少时候咱们却又不得不去跨域请求资源,这个时候就须要咱们想方法去绕过浏览器同源策略的限制了。html5
常见的跨域请求解决方法:shell
1.Jsonp 利用script标签发起get请求不会出现跨域禁止的特色实现json
2.window.name+iframe 借助中介属性window.name实现跨域
3.html5的 postMessage 主要侧重于前端通信,不一样域下页面之间的数据传递浏览器
4.Cors须要服务器设置header:Access-Control-Allow-Origin
安全
5.Nginx反向代理 能够不须要目标服务器配合,不过须要Nginx中转服务器,用于转发请求(服务端之间的资源请求不会有跨域限制)服务器
下面分别说一下经常使用几种解决方案的具体实现:cors
1 Jsonp
通常状况下因为同源策略咱们不可以经过XHR跨域去请求资源,可是咱们的script标签却能够不受此限制成功的外链到来自于其余域下的资源。利用script标签这个特色,咱们能够成功的绕过同源策略。但这种方式存在局限性,咱们只可以发起get跨域请求。具体实现:
客户端
服务端
script标签跨域发起get请求,同时传递在客户端已经注册的全局函数 process_fun 做为查询参数,服务端代码提取查询参数,并传入须要返回的数据。script标签还有一个特色,就是会当即执行调用所请求到的资源,因此这个时候服务端返回的 process_fun(data) 这一句代码会被当即执行,即把数据 data 传入咱们事先定义好的函数 process_fun 中执行进一步的处理。
2 Cors
即跨域资源共享。实现cors通讯的关键是服务器,只要服务器实现了cors接口,就能够跨源通讯。不过不一样于jsonp,cors对于IE8如下的浏览器是不支持的。
客户端
服务端
跨域资源共享在我看来是最直接也最简便的解决跨域问题的方式了,惟一的缺陷也就只是不能覆盖支持全部的浏览器。客户端不须要去作另外的改变,跟通常情况下发送的异步请求一致就行,甚至客户端根本不须要知道所请求的接口是跨域的。而服务端所须要作的也只是返回响应的同时设置 Access-Control-Allow-Origin
响应头部,意为“予许指定源(‘*’为任意源)发起跨域资源请求”。
3 window.name 和 postMessage
window.name 和 postMessage 主要都侧重于纯前端页面之间的数据通信,前者利用了 “ 在同一浏览器窗口载入的不一样页面( 不管它们是否不一样域 ),共享同一个window.name,而且都对 window.name 有读写的权限 ” 的这一特性来实现页面间的数据交换,后者则是HTML5的API,不一样域下的页面在知足必定关系的条件下能够经过此API跨域传送数据。
4 Nginx反向代理
Nginx反向代理解决跨域问题则是利用了服务端之间的资源请求不会有跨域限制的特色实现的,具体来讲就是咱们前端发起的请求被Nginx拦截,再由Nginx代由转发请求到资源服务器请求资源。
好比如今咱们有两个Nodejs服务,分别是http://127.0.0.1:3000 和 http://127.0.0.1:5000,5000端口对应的服务端下的页面须要发起请求3000端口所对应的服务端的资源,固然,在这种状况下若是不作任何的额外处理,请求会产生跨域。这个时候咱们能够用Nginx来代理转发咱们的请求,前端不去直接对资源服务器发起请求,而是改成直接访问Nginx服务器,看到这里你可能会问了,发起请求的前端页面是属于 http://127.0.0.1:5000 所在域下的,对Nginx服务发起请求难道不会和以前直接发起的请求同样出现跨域吗?因此这里须要明白的一点是,一开始咱们多是经过 http://127.0.0.1:5000/ 这样的路径访问到咱们的页面的,可是若是咱们使用Nginx做为反向代理,代理服务器监听8080端口,咱们这时候再访问该页面就再也不是访问 http://127.0.0.1:5000/ , 而是 http://127.0.0.1:8080/ 了,在Nginx中咱们再作这样的配置:
location / { proxy_pass http://127.0.0.1:5000; }
就能成功访问到首页了,而这个时候首页是在 8080 端口所对应的域下(即Nginx服务)被渲染出来的,因此首页这个时候便再也不与 http://127.0.0.1:5000 同域, 而是与 Nginx 服务同域了,也就是说前端这时候对 Nginx 服务发起请求就不会再是跨域。
访问 Nginx 咱们能够实现了,接下来要作的就是对请求进行代理转发。
前端的 Ajax 请求是这样的:
Nginx 须要对该请求进行拦截,因此能够作以下配置:
location配置的意思是对包含 “cross_origin” 请求拦截,并对请求路径进行重写,一开始请求路径是 “/cross_origin/get_json?type=20170126” ,重写后便成了 “/get_json?type=20170126”,$1表明(.*)中的内容,而(.*)则表明 cross_origin 后面的所有字符,也就是咱们会把 cross_origin 部分去掉,可是保留 cross_origin 以后的全部字符,固然这一步并不是是绝对必要的。接下来咱们再把请求代理到 3000 端口所对应的资源服务,因此请求路径从一开始的 “127.0.0.1:8080/cross_origin/get_json?type=20170126” 通过代理服务器Nginx以后变成了 “127.0.0.1:3000/get_json?type=20170126”。在 “127.0.0.1:3000” 下存在对应的接口:
如今在前端触发点击事件发起请求:
获得了响应,至此咱们成功发起了跨域请求。
完。