跨域问题的5种解决方案

跨域

什么是跨域

跨域是由浏览器的同源策源产生的,是指页面请求的接口地址,必须与页面的url地址处于同域上(即域名、端口、协议相同)。这是为了防止某域名下面的接口,被其他域名下的网页非法调用,是浏览器对JavaScript施加的安全限制。

跨域产生的原因

在我们日常的开发中,静态资源是放在本地电脑上面的,访问这些资源通常通过IP地址(127.0.0.1)或者localhost来访问的,与线上服务器所在的域名不符,不能顺利的进行接口的调用

跨域的解决办法
使用JSONP

http://blog.csdn.net/u014607184/article/details/52027879


设置代理解决跨域
正向代理

代理,也称正向代理,是指一个位于客户端和目标服务器(target server)之间的服务器,为了从目标服务器取得内容,客户端向代理发送一个请求并指定目标(目标服务器),然后代理向目标服务器转交请求并将获得的内容返回给客户端。

举个小栗子:
「客户端」可以看作一个黑社会大佬,「目标服务器」可以看作一家饭店,「代理服务器」可以看作小弟。

  • 「老大」想吃饭店的酱排骨饭,就让「小弟」去买,「小弟」跑到「饭店」要个酱排骨饭。

  • 「饭店」酱排骨饭做好,送到「小弟」手上,「小弟」最后再把酱排骨饭拿给「大佬」。

说白了,小弟就是个跑腿的,代理大佬的需求。

数据流程:

  • 数据请求过程:浏览器-》代理服务器-》目标服务器
  • 数据返回过程:目标服务器-》代理服务器-》浏览器

应用:
最经典的应用就是科学上网:我是一个国内用户,我访问不了google,但是我能访问一个香港的某个代理服务器。
这个香港的代理服务器可以访问google,于是我先把请求发送到那个代理服务器,告诉他我需要访问google,代理服务器去取内容,最后返回给我。

就好比,大佬被抓起来坐牢了,不能出去买酱排骨,只好拜托小弟去买回来。

反向代理

反向代理(Reverse Proxy)是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。

数据流程:
- 数据请求过程:浏览器 =>【反向代理服务器=>处理数据的服务器】

  • 数据返回过程:【处理数据的服务器=>反向代理服务器】=>浏览器

通俗地说:
「浏览器」可以看作食客,「【反向代理服务器-》处理数据的服务器】」这一个整体可以看作饭店,其中「反向代理服务」相当于点单的服务员。「处理数据的服务器」可以理解为是厨师。

「食客」向来到「饭店」向「服务员」点菜,但服务员并不会真正去做菜,他是下达命令让「厨师」去做菜。

「厨师」把菜做好了给「服务员」,「服务员」再把菜端给「食客」。

在外部看来,「代理服务器」和「处理数据的服务器」是一个整体。就好比,食客只会去饭店吃饭,而不是去找厨师吃饭(即对于浏览器来说,到达反向代理服务器已经完成任务了,后面的操作由反向代理服务器负责)。
具体饭店怎么操作,对食客是透明的。有可能某个服务员即当服务器也当厨师(即反向代理服务器和处理数据的服务器是同一台PC机)。

补充一下,没有反向代理,就好比没有了服务员,食客直接向厨师要吃的。譬如,你饿了,直接叫妈妈做饭是一样的(少了下订单的步骤)

比较

从用途上来讲:

  • 正向代理的典型用途是为在防火墙内的局域网客户端提供访问Internet的途径。正向代理还可以使用缓冲特性减少网络使用率。

  • 反向代理的典型用途是为后端的多台服务器提供负载平衡,或为后端较慢的服务器提供缓冲服务。

从安全性来讲:

  • 正向代理允许客户端通过它访问任意网站并且隐藏客户端自身,因此你必须采取安全措施以确保仅为经过授权的客户端提供服务。

  • 反向代理对外都是透明的,访问者并不知道自己访问的是一个代理。

从使用方来看:

  • 正向代理是浏览器端进行配置的,与服务器端无关,甚至可以对服务端隐藏。
  • 反向代理是服务器端配置的,对浏览器端是透明的。

利用正向代理实现跨域
实现原理

对正向代理服务器进行配置,当获取非接口数据时,让代理服务器指向开发者本机的资源。当访问接口时,访问后端接口数据

相当于大佬让小弟把酱排骨饭里面的饭和酱排骨分开买,饭自己家煮,酱排骨才去饭店买。

程序运行过程

  1. 浏览器访问页面,假设访问淘宝页面:taobao.com/index.html(假设这个页面中调用了taobao.com/api/getNew获取最新商品的接口)

  2. taobao.com/index.html请求经过代理服务器,根据配置,index.html页面请求127.0.0.1:3000

  3. 127.0.0.1:3000返回index.html文件给浏览器。

  4. 浏览器运行index.html页面,发起taobao.com/api/getNew请求。

  5. taobao.com/api/getNew请求经过代理服务器,但由于没有对这个接口进行特殊配置,这个接口会正常访问道淘宝服务器。

  6. 淘宝服务器接受到taobao.com/api/getNew请求,检查请求头的hosts字段,发现是taobao.com,没有跨域,将结果返回给代理服务器。

  7. 代理服务器拿到结果,返回给浏览器,浏览器进行解析显示。

  8. 代理配置(以mac下的charles为例)

利用反向代理实现跨域
反向代理需要用到nginx,再此不做过多介绍(自己动手,丰衣足食o!)
实现原理

原理大体相同,但是处理的端不同,反向代理是在服务器端进行处理。首先修改hosts文件,将域名指向开发者的电脑本身,把自己伪装成服务端,再通过nginx对不同的请求进行转发,把静态资源指向开发者本地电脑的资源,将接口指向实际的服务器。

相当于把饭店设置在了黑社会的楼下,去楼下买酱排骨饭的时候,饭店米饭自己做,酱排骨则偷偷跑去别的饭店买。

代理配置
1. 设置hosts文件,将目标域名指向本机。

  1. 编辑nginx配置,对不同的资源请求,指向到对应地址。同样的,将静态资源指向本机服务,将接口指向真正的服务器。

  2. 程序运行过程
    浏览器访问页面,假设访问淘宝页面:taobao.com/index.html

  3. taobao.com域名解析先经过hosts文件配置,发现taobao.com域名指向127.0.0.1,则向本机发起请求。

  4. nginx接收到taobao.com/index.html请求,根据nginx的配置,将把这个请求转发给127.0.0.1:3000。

  5. 浏览器运行index.html文件,发起taobao.com/api/getNew请求

  6. nginx接收到taobao.com/api/getNew请求请求,根据nginx的配置,将把这个请求转发给真正的淘宝服务器中。

  7. 淘宝服务器将数据返回给nginx,再返回给浏览器执行。

简单的对比

  • 使用charles等正向代理方式比较简单,需要掌握的知识点也比较少。但相应的其可配置性较弱,仅适合中小型项目使用。

  • 使用nginx的反向代理则相对复杂一些,需要了解基本的nginx配置。但其可配置性较强,支持URL的正则匹配,设置优先级等,适合复杂的项目使用。

使用跨域资源共享(CORS)

CORS(Cross-Origin Resource Sharing)跨域资源共享,定义了必须在访问跨域资源时,浏览器与服务器应该如何沟通。CORS背后的基本思想就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是失败。
使用方法也很简单,在php后端设置 Access-Control-Allow-Origin 头即可

嵌入iframe

不同的框架之间是可以获取window对象的,但却无法获取相应的属性和方法。
比如,有一个页面,它的地址是http://www.example.com/a.html
在这个页面里面有一个iframe,它的src是http://example.com/b.html,
很显然,这个页面与它里面的iframe框架是不同域的,所以我们是无法通过在页面中书写js代码来获取iframe中的东西的
这个时候,document.domain就可以派上用场了,
我们只要把http://www.example.com/a.htmlhttp://example.com/b.html这两个页面的document.domain都设成相同的域名就可以了。
但要注意的是,document.domain的设置是有限制的,我们只能把document.domain设置成自身或更高一级的父域,且主域必须相同。

使用window.postMessage方法

这个东西是HTML5引入的,可以在不同的window下传递数据,不受域的影响。目前IE8+、FireFox、Chrome、Opera等浏览器都已经支持该方法
window.postMessage(message,targetOrigin)
调用postMessage方法的window对象是指要接收消息的那一个window对象,该方法的第一个参数message为要发送的消息,类型只能为字符串;
第二个参数targetOrigin用来限定接收消息的那个window对象所在的域,如果不想限定域,可以使用通配符 * 。
需要接收消息的window对象,可是通过监听自身的message事件来获取传过来的消息,消息内容储存在该事件对象的data属性中。

/*
 * A窗口的域名是<http://example.com:8080>,以下是A窗口的script标签下的代码:
 */

var popup = window.open(...popup details...);

// 如果弹出框没有被阻止且加载完成

// 这行语句没有发送信息出去,即使假设当前页面没有改变location(因为targetOrigin设置不对)
popup.postMessage("The user is 'bob' and the password is 'secret'",
                  "https://secure.example.net");

// 假设当前页面没有改变location,这条语句会成功添加message到发送队列中去(targetOrigin设置对了)
popup.postMessage("hello there!", "http://example.org");

function receiveMessage(event)
{
  // 我们能相信信息的发送者吗?  (也许这个发送者和我们最初打开的不是同一个页面).
  if (event.origin !== "http://example.org")
    return;

  // event.source 是我们通过window.open打开的弹出页面 popup
  // event.data 是 popup发送给当前页面的消息 "hi there yourself!  the secret response is: rheeeeet!"
}
window.addEventListener("message", receiveMessage, false);
/*
 * 弹出页 popup 域名是<http://example.org>,以下是script标签中的代码:
 */

//当A页面postMessage被调用后,这个function被addEventListenner调用
function receiveMessage(event)
{
  // 我们能信任信息来源吗?
  if (event.origin !== "http://example.com:8080")
    return;

  // event.source 就当前弹出页的来源页面
  // event.data 是 "hello there!"

  // 假设你已经验证了所受到信息的origin (任何时候你都应该这样做), 一个很方便的方式就是把enent.source
  // 作为回信的对象,并且把event.origin作为targetOrigin
  event.source.postMessage("hi there yourself!  the secret response " +
                           "is: rheeeeet!",
                           event.origin);
}

window.addEventListener("message", receiveMessage, false);

例子来自:https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值