原文地址https://segmentfault.com/a/1190000003642057

超详细并且带 Demo 的 JavaScript 跨域指南来了!

本文基于你了解 JavaScript 的同源策略,并且了解使用跨域跨域的理由。

1. JSONP

首先要介绍的跨域方法必然是 JSONP。

现在你想要获取其他网站上的 JavaScript 脚本,你非常高兴的使用 XMLHttpRequest 对象来获取。但是浏览器一点儿也不配合你,无情的弹出了下面的错误信息:

XMLHttpRequest cannot load http://x.com/main.dat. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://y.com' is therefore not allowed access.

你心里肯定会想,我难道要用后台做个爬虫来获取这个数据吗?!(;°○° )为了避免这种蛋疼的事情发生,JSONP 就派上用场了。

<script> 标签是不受同源策略的限制的,它可以载入任意地方的 JavaScript 文件,而并不要求同源。

所以 JSONP 的理念就是,我和服务端约定好一个函数名,当我请求文件的时候,服务端返回一段 JavaScript。这段 JavaScript 调用了我们约定好的函数,并且将数据当做参数传入。非常巧合的一点(其实并不是),JSON 的数据格式和 JavaScript 语言里对象的格式正好相同。所以在我们约定的函数里面可以直接使用这个对象。

光说不练假把式,让我们来看一个例子:

你需要获取数据的页面 index.html:

<script>
function getWeather(data) {
console.log(data);
}
</script> <script src="http://x.y.com/xx.js">

http://x.y.com/xx.js 文件内容:

getWeather({
"城市": "北京",
"天气": "大雾"
});

我们可以看到,在我们定义了 getWeather(data) 这个函数后,直接载入了 xx.js。
在这个脚本中,执行了 getWeather 函数,并传入了一个对象。然后我们在这个函数中将这个对象输出到 console 中。

这就是整个 JSONP 的流程。

2. document.domain

使用条件:

  1. 有其他页面 window 对象的引用。

  2. 二级域名相同。

  3. 协议相同。

  4. 端口相同。

document.domain 默认的值是整个域名,所以即使两个域名的二级域名一样,那么他们的 document.domain 也不一样。

使用方法就是将符合上述条件页面的 document.domain 设置为同样的二级域名。这样我们就可以使用其他页面的 window 对象引用做我们想做的任何事情了。(╯▔▽▔)╯

补充知识:

  • x.one.example.com 和 y.one.example.com 可以将 document.domain 设置为 one.example.com,也可以设置为 example.com。

  • document.domain 只能设置为当前域名的一个后缀,并且包括二级域名或以上(.edu.cn 这种整个算顶级域名)。

我们直接操刀演示,用两个网站 http://wenku.baidu.com/ 和 http://zhidao.baidu.com/
这两个网站都是 http 协议,端口都是 80, 且二级域名都是 baidu.com。

打开 http://wenku.baidu.com/,在 console 中输入代码:

document.domain = 'baidu.com';

var otherWindow = window.open('http://zhidao.baidu.com/');

我们现在已经发现百度知道的网页已经打开了,在百度知道网页的 console 中输入以下代码:

document.domain = 'baidu.com';

现在回到百度文库的网页,我们就可以使用百度知道网页的 window 对象来操作百度知道的网页了。例如:

var divs = otherWindow.document.getElementsByTagName('div');

上面这个例子的使用方法并不常见,但是非常详细的说明了这种方法的原理。
这种方法主要用在控制 <iframe> 的情况中。

比如我的页面(http://one.example.com/index....中内嵌了一个 <iframe>

<iframe id="iframe" src="http://two.example.com/iframe.html"></iframe>

我们在 iframe.html 中使用 JavaScript 将 document.domain 设置好,也就是 example.com。

在 index.html 执行以下脚本:

var iframe = document.getElementById('iframe');

document.domain = 'example.com';

iframe.contentDocument; // 框架的 document 对象
iframe.contentWindow; // 框架的 window 对象

这样,我们就可以获得对框架的完全控制权了。

补充知识(绝对干货):
当两个页面不做任何处理,但是使用了框架或者 window.open() 得到了某个页面的 window 对象的引用,我们可以直接访问的属性有哪些?

方法
window.blur
window.close
window.focus
window.postMessage
window.location.replace
属性 权限
window.closed 只读
window.frames 只读
window.length 只读
window.location.href 只写
window.opener 只读
window.parent 只读
window.self 只读
window.top 只读
window.window 只读

3. window.name

我们来看以下一个场景:

随意打开一个页面,输入以下代码:

window.name = "My window's name";
location.href = "http://www.qq.com/";

再检测 window.name :

window.name; // My window's name

可以看到,如果在一个标签里面跳转网页的话,我们的 window.name 是不会改变的。
基于这个思想,我们可以在某个页面设置好 window.name 的值,然后跳转到另外一个页面。在这个页面中就可以获取到我们刚刚设置的 window.name 了。

由于安全原因,浏览器始终会保持 window.name 是 string 类型。

这个方法也可以应用到与 <iframe> 的交互上来。

我的页面(http://one.example.com/index....中内嵌了一个 <iframe>

<iframe id="iframe" src="http://omg.com/iframe.html"></iframe>

在 iframe.html 中设置好了 window.name 为我们要传递的字符串。
我们在 index.html 中写了下面的代码:

var iframe = document.getElementById('iframe');
var data = ''; iframe.onload = function() {
data = iframe.contentWindow.name;
};

定睛一看,为毛线报错?
细心的读者们肯定已经发现了,两个页面完全不同源啊!
由于 window.name 不随着 URL 的跳转而改变,所以我们使用一个暗黑技术来解决这个问题:

var iframe = document.getElementById('iframe');
var data = ''; iframe.onload = function() {
iframe.onload = function(){
data = iframe.contentWindow.name;
}
iframe.src = 'about:blank';
};

或者将里面的 about:blank 替换成某个同源页面(最好是空页面,减少加载时间)。

补充知识:
about:blankjavascript: 和 data: 中的内容,继承了载入他们的页面的源。

这种方法与 document.domain 方法相比,放宽了域名后缀要相同的限制,可以从任意页面获取 string 类型的数据。

4. [HTML5] postMessage

在 HTML5 中, window 对象增加了一个非常有用的方法:

windowObj.postMessage(message, targetOrigin);
  • windowObj: 接受消息的 Window 对象。

  • message: 在最新的浏览器中可以是对象。

  • targetOrigin: 目标的源,* 表示任意。

这个方法非常强大,无视协议,端口,域名的不同。下面是烤熟的栗子:

var windowObj = window; // 可以是其他的 Window 对象的引用
var data = null; addEventListener('message', function(e){
if(e.origin == 'http://jasonkid.github.io/fezone') {
data = e.data; e.source.postMessage('Got it!', '*');
}
});

message 事件就是用来接收 postMessage 发送过来的请求的。函数参数的属性有以下几个:

  • origin: 发送消息的 window 的源。

  • data: 数据。

  • source: 发送消息的 Window 对象。

Demo

https://github.com/JasonKid/f...

两种服务端相关跨域方法

「JavaScript」两种服务端相关跨域方法详解 ← 反向代理、CORS方法请点这里

觉得不错的话按顶部的推荐,让更多人看到吧~ㄟ(▔▽▔ㄟ)

「JavaScript」JS四种跨域方式详解的更多相关文章

  1. 「JavaScript」四种跨域方式详解

    超详细并且带 Demo 的 JavaScript 跨域指南来了! 本文基于你了解 JavaScript 的同源策略,并且了解使用跨域跨域的理由. 1. JSONP 首先要介绍的跨域方法必然是 JSON ...

  2. JAVA中的四种JSON解析方式详解

    JAVA中的四种JSON解析方式详解 我们在日常开发中少不了和JSON数据打交道,那么我们来看看JAVA中常用的JSON解析方式. 1.JSON官方 脱离框架使用 2.GSON 3.FastJSON ...

  3. thinkphp四种url访问方式详解

    本文实例分析了thinkphp的四种url访问方式.分享给大家供大家参考.具体分析如下: 一.什么是MVC thinkphp的MVC模式非常灵活,即使只有三个中和一个也可以运行. M -Model 编 ...

  4. Android学习笔记_50_(转 四种加载方式详解(standard singleTop singleTask singleInstance)

    Android之四种加载方式 (http://marshal.easymorse.com/archives/2950 图片) 在多Activity开发中,有可能是自己应用之间的Activity跳转,或 ...

  5. Android 四种加载方式详解(standard singleTop singleTask singleInstance) .

    Android之四种加载方式 (http://marshal.easymorse.com/archives/2950 图片) 在多Activity开发中,有可能是自己应用之间的Activity跳转,或 ...

  6. VirtualBox的四种网络连接方式详解

    VirtualBox中有4中网络连接方式: 1. NAT 2. Bridged Adapter 3. Internal 4. Host-only Adapter VMWare中有三种,其实他跟VMWa ...

  7. SpringDI四种依赖注入方式详解

    文章已托管到GitHub,大家可以去GitHub查看阅读,欢迎老板们前来Star!搜索关注微信公众号 [码出Offer] 领取各种学习资料! LOGO SpringDI(依赖注入) 一.DI概述 De ...

  8. Javascript几种跨域方式总结

    在客户端编程语言中如javascript,同源策略规定跨域之间的脚本是隔离的,一个域的脚本不能访问和操作另外一个域的绝大部分属性和方法.只有当两个域具有相同的协议,相同的主机,相同的端口时,我们就认定 ...

  9. 从壹开始前后端分离【 .NET Core2.0 +Vue2.0 】框架之十二 || 三种跨域方式比较,DTOs(数据传输对象)初探

    更新反馈 1.博友@落幕残情童鞋说到了,Nginx反向代理实现跨域,因为我目前还没有使用到,给忽略了,这次记录下,为下次补充.此坑已填 2.提示:跨域的姊妹篇——<三十三║ ⅖ 种方法实现完美跨 ...

随机推荐

  1. 菜鸟玩云计算之十八:Hadoop 2.5.0 HA 集群安装第1章

    菜鸟玩云计算之十八:Hadoop 2.5.0 HA 集群安装第1章 cheungmine, 2014-10-25 0 引言 在生产环境上安装Hadoop高可用集群一直是一个需要极度耐心和体力的细致工作 ...

  2. 使用Android Studio手把手教你将应用打包+代码混淆

    最近几天用Google的Design库写了个App,使用Android Studio将app打包时遇到的几个瓶颈,所以把详细步骤写入下来. AS中怎么获取应用签名 这和eclipse不同,eclips ...

  3. c/c++ 表达式求值

    表达式求值 [问题描述] 一个算术表达式是由操作数(operand).运算符(operator)和界限符(delimiter)组成的.假设操作数是正整数,运算符只含加减乘除等四种运算符,界限符有左右括 ...

  4. Android开发技巧——自定义控件之自定义属性

    Android开发技巧--自定义控件之自定义属性 掌握自定义控件是很重要的,因为通过自定义控件,能够:解决UI问题,优化布局性能,简化布局代码. 上一篇讲了如何通过xml把几个控件组织起来,并继承某个 ...

  5. C++之多继承

    #include <iostream> using namespace std ; class AA { public: int a ; void Say_hello(void) { co ...

  6. 图片验证码demo示例

    1.首先我们需要一个生成图片验证码图片的一个工具类(下方会有代码示例) 代码如下: package com.util; import java.awt.BasicStroke; import java ...

  7. pyqt5 动画在QThread线程中无法运行问题

    自己做了一个tcp工具,在学习动画的时候踩了坑,需求是根据上线变绿色,离线变灰色,如果连接断开了,则变为灰色 问题现象: 可以看到点击"连接","离线"的时候动 ...

  8. azkaban的安装部署

    一.所需环境 1,JDK 2,HADOOP 4,mysql 3,HIVE 二.安装azkaban 1,安装git命令: yum install git 2,下载azkaban源码:git clone ...

  9. ffmpeg 时间戳处理

    视频的显示和存放原理 对于一个电影,帧是这样来显示的:I B B P.现在我们需要在显示B帧之前知道P帧中的信息.因此,帧可能会按照这样的方式来存储:IPBB.这就是为什么我们会有一个解码时间戳和一个 ...

  10. Windows 10创意者更新ISO发布!官方下载

    http://news.mydrivers.com/1/526/526719.htm 去年7月份,微软面向Windows 10推出了“周年更新”,让系统变得更加稳定好用.今天,Windows 10迎来 ...