一、神马是跨域(Cross Domain)

说白点就是post、get的url不是你当前的站点,域名不同。比如在*aaa.com/a.html*里面,表单的提交action是bbb.com/b.html

不仅如此,www.aaa.comaaa.com之间也属于跨域。由于www.aaa.com是二级域名,aaa.com是根域名。

JavaScript出于安全方面的考虑,是不同意跨域调用其它页面的对象的(同源策略 Same-Origin Policy)。

特别注意两点:

  • 第一。假设是协议和端口造成的跨域问题“前台”是无能为力的。
  • 第二:在跨域问题上。域仅仅是通过“URL的首部”来识别而不会去尝试推断同样的ip地址相应着两个域或两个域是否在同一个ip上。

    “URL的首部”指window.location.protocol +window.location.host,也能够理解为“Domains, protocols and ports must match”。

二、为嘛要跨域

跨域这东西事实上非经常见,比如我们能够把站点的一些脚本、图片或其它资源放到另外一个站点。

比如我们能够使用Google提供的jQuery,载入时间少了,而且降低了server的流量,例如以下:

<script type="text/java script" src="https://aja x.googleapis.com/aj ax/libs/jquery/1.4.2/jquery.min.js"></script>

跨域问题产生的场景

有时候不仅仅是一些脚本、图片这样的资源,我们也会希望从另外的站点调用一些数据(有时候是不得不这样)。比如我希望获取一些blog的RSS来生成一些内容,再或者说我在“人人开放平台”上开发一个应用。须要调用人人的数据。

当要在在页面中使用js获取其它站点的数据时。就会产生跨域问题,比方在站点中使用ajax请求其它站点的天气、快递或者其它数据接口时以及hybrid app中请求数据,浏览器就会提示以下错误。

这样的场景下就要解决js的跨域问题。

然而,非常不幸的是,直接用XMLHttpRequest来Get或者Post是不行的。比如我用jQuery的$.get去訪问例如以下主域名 :

$.get("http://flycoder.org/",
{}, function(data){
alert('跨域不是越狱:'+data)
}, "html");

结果例如以下(总之就是不行啦~FF不报错,可是木有返回数据):

那咋么办捏?(弱弱的说,測试的时候我发现IE訪问本地文件时,是能够跨域的,只是这也没啥用~囧~)

三、肿么跨域

在浏览器中,<script><img><iframe><link>这几个标签是能够载入跨域(非同源)的资源的,而且载入的方式事实上相当于一次普通的GET请求,唯一不同的是,为了安全起见,浏览器不同意这样的方式下对载入到的资源的读写操作,而仅仅能使用标签本身应当具备的能力(比方脚本运行、样式应用等等)。

最常见的跨域问题是Ajax跨域訪问的问题,默认情况下,跨域的URL是无法通过Ajax訪问的。这里我记录我所了解到的跨域的方法:

  1. server端代理,这没有什么可说的。缺点在于,默认情况下接收Ajax请求的服务端是无法获取到的client的IP和UA的。

  2. iframe,使用iframe事实上相当于开了一个新的网页,详细跨域的方法大致是,域A打开的母页面嵌套一个指向域B的iframe,然后提交数据。完毕之后,B的服务端能够:

    ●返回一个302重定向响应,把结果又一次指回A域;

    ●在此iframe内部再嵌套一个指向A域的iframe。

这两者都终于实现了跨域的调用。这种方法功能上要比以下介绍到的JSONP更强。由于跨域完毕之后DOM操作和互相之间的JavaScript调用都是没有问题的。可是也有一些限制,比方结果要以URL參数传递,这就意味着在结果数据量非常大的时候须要切割传递,甚是麻烦;另一个麻烦是iframe本身带来的。母页面和iframe本身的交互本身就有安全性限制。

3、 利用script标签跨域,这个办法也非经常见。script标签是能够载入异域的JavaScript并运行的,通过预先设定好的callback函数来实现和母页面的交互。它有一个大名。叫做JSONP跨域。JSONP是JSON with Padding的略称。

它是一个非官方的协议,明明是载入script,为啥和JSON扯上关系呢?原来就是这个callback函数。对它的使用有一个典型的方式,就是通过JSON来传參,即将JSON数据填充进回调函数,这就是JSONP的JSON+Padding的含义。以下详细介绍一下。

为了更好的解说和測试,我们能够通过改动hosts文件来模拟跨域的效果。hosts文件在C:\Windows\System32\drivers\etc 目录下。在以下加3行:

127.0.0.1 www.a.com

127.0.0.1 a.com

127.0.0.1 www.b.com

3.1、跨域代理

一种简单的办法。就是把跨域的工作交给server。从后台获取其它站点的数据再返回给前台,也就是跨域代理(Cross Domain Proxy)。

这样的方法似乎蛮简单的。改动也不太大。只是就是http请求多了些,响应慢了些。server的负载重了些~

3.2、document.domain+iframe的设置

对于主域同样而子域不同的样例,能够通过设置document.domain的办法来解决。

举www.a.com/a.html和a.com/b.html为例.

思路:仅仅需在a.html中加入一个b.html的iframe,而且设置两个页面的document.domain都为’a.com’(仅仅能为主域名)。两个页面之间即可互相訪问了。代码例如以下:

www.a.com/a.html中的script

<!DOCTYPE HTML>
<html>
<head>
<meta name="name" content="content" charset="utf-8">
</head>
<body>
<script type="text/javascript">
document.domain='a.com';
var ifr = document.createElement('iframe');
ifr.src = 'http://a.com/b.html';
ifr.style.display = 'none';
document.body.appendChild(ifr);
ifr.onload = function(){
//获取iframe的document对象
//W3C的标准方法是iframe.contentDocument,
//IE6、7能够使用document.frames[ID].document
//为了更好兼容,可先获取iframe的window对象iframe.contentWindow
var doc = ifr.contentDocument || ifr.contentWindow.document;
// 在这里操纵b.html
alert(doc.getElementById("test").innerHTML);
};
</script>
</body>
</html>

备注:某一页面的domain默认等于window.location.hostname。

主域名是不带www的域名,比如a.com。主域名前面带前缀的通常都为二级域名或多级域名,比如www.a.com事实上是二级域名。

domain仅仅能设置为主域名。不能够在b.a.com中将domain设置为c.a.com。

a.com/b.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title></title>
<script type="text/javascript">
document.domain='a.com';
</script>
</head>
<body>
<h1 id="test">Hello World</h1>
</body>
</html>

假设b.html要訪问a.html,可在子窗体(iframe)中通过window.parent来訪问父窗体的window对象,然后就能够为所欲为了(window对象都有了,还有啥不行的),同理子窗体也能够和子窗体之间通信。

于是,我们能够通过b.html的XMLHttpRequest来获取数据,再传给a.html。从而解决跨子域获取数据的问题。

可是这样的方法仅仅支持同一根域名下的页面。假设不同根域名(比如baidu.com想訪问google.com)那就无能为力了。

问题:

  • 1、安全性,当一个站点(b.a.com)被攻击后,另一个站点(c.a.com)会引起安全漏洞。

  • 2、假设一个页面中引入多个iframe,要想能够操作全部iframe,必须都得设置同样domain。

3.3、动态script标签(Dynamic Script Tag)

尽管浏览器默认禁止了跨域訪问。但并不禁止在页面中引用其它域的JS文件,并能够自由运行引入的JS文件里的function(包含操作cookie、Dom等等)。依据这一点。能够方便地通过创建script节点的方法来实现全然跨域的通信。

这样的方法也叫“动态脚本注入”。

这样的技术克服了XMLHttpRequest的最大限制,也就是跨域请求数据。直接用JavaScript创建一个新的脚本标签,然后设置它的src属性为不同域的URL。

www.a.com/a.html中的script

var dynScript = document.createElement('script');
dynScript.src = 'http://www.b.com/b.js';
dynScript.setAttribute("type", "text/javascript");
document.getElementsByTagName('head')[0].appendChild(dynScript);

通过动态标签注入的必须是可运行的JavaScript代码,因此不管是你的数据格式是啥(xml、json等),都必须封装在一个回调函数中。一个回调函数例如以下:

www.a.com/a.html中的script

function dynCallback(data){
//处理数据, 此处简单示意一下
alert(data.content);
}

在这个样例中。www.b.com/b.js须要将数据封装在上面这个dynCallback函数中。例如以下:

dynCallback({content:'来自b.com/b.js的消息Hello World!'});

我们看到了让人开心的结果。Hello World~

只是动态脚本注入还是存在不少问题的,以下我们拿它和XMLHttpRequest来对照一下:

能够看出,动态脚本注入还是有不少限制,仅仅能使用Get。不能像XHR一样推断Http状态等。

而且使用动态脚本注入的时候必须注意安全问题。由于JavaScript没有不论什么权限与訪问控制的概念。通过动态脚本注入的代码能够全然控制整个页面。所以引入外部来源的代码必须多加小心。

3.4 利用iframe和location.hash

这个办法比較绕,可是能够解决全然跨域情况下的脚步置换问题。原理是利用location.hash来进行传值。

  • ww.a.com下的a.html想和www.b.com下的b.html通信(在a.html中动态创建一个b.html的iframe来发送请求)。

  • 可是由于“同源策略”的限制他们无法进行交流(b.html无法返回数据),于是就找个中间人:www.a.com下的c.html(注意是www.a.com下的);

  • b.html将数据传给c.html(b.html中创建c.html的iframe)。由于c.html和a.html同源,于是可通过c.html将返回的数据传回给a.html。从而达到跨域的效果。

三个页面之间传递參数用的是location.hash(也就是www.a.html#sayHello后面的’#sayHello’)。改变hash并不会导致页面刷新(这点非常重要)。

详细代码例如以下:

www.a.com/a.html

//通过动态创建iframe的hash发送请求
function sendRequest(){
var ifr = document.createElement('iframe');
ifr.style.display = 'none';
//跨域发送请求给b.html, 參数是sayHello
ifr.src = 'http://www.b.com/b.html#sayHello';
document.body.appendChild(ifr);
}
//获取返回值的方法
function checkHash() {
var data = location.hash ? location.hash.substring(1) : '';
if (data) {
//处理返回值
alert(data);
location.hash='';
}
}
//定时检查自己的hash值
setInterval(checkHash, 2000);
window.onload = sendRequest;

www.b.com/b.html

function checkHash(){
var data = '';
//模拟一个简单的參数处理操作
switch(location.hash){
case '#sayHello': data = 'HelloWorld';break;
case '#sayHi': data = 'HiWorld';break;
default: break;
}
data && callBack('#'+data);
}
function callBack(hash){
// ie、chrome的安全机制无法改动parent.location.hash,
// 所以要利用一个中间的www.a.com域下的代理iframe
var proxy = document.createElement('iframe');
proxy.style.display = 'none';
// 注意该文件在"www.a.com"域下
proxy.src = 'http://www.a.com/c.html'+hash;
document.body.appendChild(proxy);
}
window.onload = checkHash;

www.a.com/c.html

//由于c.html和a.html属于同一个域。
//所以能够改变其location.hash的值
//可通过parent.parent获取a.html的window对象
parent.parent.location.hash = self.location.hash.substring(1);

可能有人会有疑问。既然c.html已经获取了a.html的window对象了。为何不直接改动它的dom或者传递參数给某个变量呢?

原因是在c.html中改动 a.html的dom或者变量会导致页面的刷新。a.html会又一次訪问一次b.html,b.html又会訪问c.html。造成死循环……囧呀~

所以仅仅能通过location.hash了。这样做也有些不好的地方,诸如数据容量是有限的(受url长度的限制),而且数据暴露在url中(用户能够任意改动)……

3.5、postMessage(html5)

HTML5中最酷的新功能之中的一个就是 跨文档消息传输Cross Document Messaging。下一代浏览器都将支持这个功能:Chrome 2.0+、Internet Explorer 8.0+, Firefox 3.0+, Opera 9.6+, 和 Safari 4.0+ 。

Facebook已经使用了这个功能,用postMessage支持基于web的实时消息传递。

otherWindow.postMessage(message, targetOrigin);

  • otherWindow: 对接收信息页面的window的引用。能够是页面中iframe的contentWindow属性;window.open的返回值;通过name或下标从window.frames取到的值。

  • message: 所要发送的数据,string类型。
  • targetOrigin: 用于限制otherWindow,“*”表示不作限制
  • a.com/index.html中的代码:

<iframe id="ifr" src="http://www.b.com/b.html"></iframe>
<script>
window.onload = function() {
var ifr = document.getElementById('ifr');
// 若写成'http://www.c.com'就不会运行postMessage了
var targetOrigin = 'http://www.b.com';
ifr.contentWindow.postMessage('sayHello', targetOrigin);
};

b.com/b.html中的代码:

//通过message事件来通信,实在太爽了
window.addEventListener('message', function(e){
// 通过origin属性推断消息来源地址
if (e.origin == 'http://www.a.com' &&
e.data=='sayHello') {
alert('Hello World');
}
}, false);

3.5 使用window.name来进行跨域

window对象有个name属性。该属性有个特征:即在一个窗体(window)的生命周期内,窗体载入的全部的页面都是共享一个window.name的,每一个页面对window.name都有读写的权限。window.name是持久存在一个窗体载入过的全部页面中的,并不会因新页面的载入而进行重置。

比方:有一个页面www.a.com/a.html它里面有这样的代码:

<script type="text/javascript">
window.name = "我是a.html的window.name";
setTimeout(function(){
window.location = 'b.html';
},3000);

再看看www.a.com/b.html页面的代码:

<script type="text/javascript">
alert(window.name);
</script>

我们看到在b.html页面上成功获取到了它的上一个页面a.html给window.name设置的值。假设在之后全部载入的页面都没对window.name进行改动的话,那么全部这些页面获取到的window.name的值都是a.html页面设置的那个值。

当然,假设有须要,其中的不论什么一个页面都能够对window.name的值进行改动。

注意,window.name的值仅仅能是字符串的形式。这个字符串的大小最大能同意2M左右甚至更大的一个容量。详细取决于不同的浏览器,但通常是够用了。

上面的样例中。我们用到的页面a.html和b.html是处于同一个域的,可是即使a.html与b.html处于不同的域中。上述结论同样是适用的,这也正是利用window.name进行跨域的原理。

以下就来看一看详细是怎么样通过window.name来跨域获取数据的。还是举例说明。

比方有一个www.a.com/a.html页面,须要通过a.html页面里的js来获取另一个位于不同域上的页面www.b.com/b.html里的数据。

b.html页面里的代码非常easy,就是给当前的window.name设置一个a.html页面想要得到的数据值。b.html里的代码:

<script type="text/javascript">
window.name ="我就是页面a.html想要的数据,全部能够转化成字符串的数据都能够在这里使用。比方一个json数据";
</script>

那么在a.html页面中,我们怎么把data.html页面载入进来呢?显然我们不能直接在a.html页面中通过改变window.location来载入data.html页面,由于我们想要即使a.html页面不跳转也能得到data.html里的数据。答案就是在a.html页面中使用一个隐藏的iframe来充当一个中间人角色,由iframe去获取data.html的数据,然后a.html再去得到iframe获取到的数据。

充其中间人的iframe想要获取到data.html的通过window.name设置的数据。仅仅须要把这个iframe的src设为www.cnblogs.com/data.html即可了。然后a.html想要得到iframe所获取到的数据,也就是想要得到iframe的window.name的值。还必须把这个iframe的src设成跟a.html页面同一个域才行,不然依据前面讲的同源策略,a.html是不能訪问到iframe里的window.name属性的。这就是整个跨域过程。

看下a.html页面的代码:

<script type="text/javascript">
function getData(){
var ifr = document.getElementById('proxy');
ifr.onload = function(){//这个时候a.html与ifr已经是同源了,能够相互訪问
var data= ifr.contentWindow.name;//获取iframe里的数据,也就是data.html页面设置的数据
alert(data);//成功获得了数据。
}
ifr.src='about:blank';//这里的about:blank能够是随便的一个页面,仅仅要与a.html同源就能够,目的是让a.html能够訪问到iframe里的数据。 }
</script>
<iframe id="proxy" src="http://www.b.com/b.html" style="display: none" onload="getData()"></iframe>

上面的代码仅仅是最简单的原理演示代码。你能够对使用js封装上面的过程,比方动态的创建iframe,动态的注冊各种事件等等,当然为了安全,获取完数据后,还能够销毁作为代理的iframe。网上也有非常多相似的现成代码。有兴趣的能够去找一下。

通过window.name来进行跨域,就是这样子的。

3.6 通过jsonp跨域

在js中,我们直接用XMLHttpRequest请求不同域上的数据时。是不能够的。可是,在页面上引入不同域上的js脚本文件却是能够的,jsonp正是利用这个特性来实现的。

json≠jsonp

原理

jsonp解决跨域问题的原理是,浏览器的script标签是不受同源策略限制(你能够在你的网页中设置script的src属性问cdnserver中静态文件的路径)。那么就能够使用script标签从server获取数据,请求时加入一个參数为callbakc=?,?号时你要运行的回调方法。

比方,有个www.a.com/a.html页面。它里面的代码须要利用ajax获取一个不同域上的json数据。假设这个json数据地址是http://www.b.com/b.php,那么a.html中的代码就能够这样:

<script type="text/javascript">
function dosomething(jsondata){
//处理json数据
}
</script>
<script src="http://www.b.com/b.php?callback=dosomething"></script>

我们看到获取数据的地址后面另一个callback參数,按惯例是用这个參数名,可是你用其它的也一样。

当然假设获取数据的jsonp地址页面不是你自己能控制的,就得依照提供数据的那一方的规定格式来操作了。

由于是当做一个js文件来引入的。所以http://www.b.com/b.php返回的必须是一个能运行的js文件,所以这个页面的php代码可能是这样的:

<?php
$callback = $_GET['callback'];//得到回调函数
$data = array('a','b','c','d');//要返回的数据
echo $callback.'('.json_encode($data).')';//输出
?>

终于那个页面输出的结果是:

所以通过http://www.b.com/b.php?callback=dosomething得到的js文件,就是我们之前定义的dosomething函数,而且它的參数就是我们须要的json数据,这样我们就跨域获得了我们须要的数据。

这样jsonp的原理就非常清楚了,通过script标签引入一个js文件,这个js文件载入成功后会运行我们在url參数中指定的函数,而且会把我们须要的json数据作为參数传入。所以jsonp是须要server端的页面进行相应的配合的。

知道jsonp跨域的原理后我们就能够用js动态生成script标签来进行跨域操作了,而不用特意的手动的书写那些script标签。假设你的页面使用jquery,那么通过它封装的方法就能非常方便的来进行jsonp操作了。

<script type="text/javascript">
$getJSON('http://www.b.com/b.php?callback=?',function(jsondata){
//处理获得的json数据;
});

原理是一样的,仅仅只是我们不须要手动的插入script标签以及定义回掉函数。

jquery会自己主动生成一个全局函数来替换callback=?

中的问号。之后获取到数据后又会自己主动销毁,实际上就是起一个暂时代理函数的作用。$.getJSON方法会自己主动推断是否跨域。不跨域的话。就调用普通的ajax方法。跨域的话,则会以异步载入js文件的形式来调用jsonp的回调函数。

四、总结

研究了几天,尽管对多种跨域方法都有所了解了,可是真要投入应用还是明显不够的(还是须要借助一些js库)。

每种方法都有其优缺点,使用的时候事实上应该将多种跨域方法进一步封装一下,统一调用的接口,利用js来自己主动推断哪种方法更为适用 。

你不知道的JavaScript--Item33 跨域总结与解决的方法的更多相关文章

  1. ajax 跨域 headers JavaScript ajax 跨域请求 +设置headers 实践

    解决跨域调用服务并设置headers 主要的解决方法需要通过服务器端设置响应头.正确响应options请求,正确设置 JavaScript端需要设置的headers信息 方能实现. 此处手札 供后人参 ...

  2. WebApi2跨域问题及解决办法

    跨域问题产生的原因 同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能.现在所有支持JavaScript的浏览器都会使用这个策略.所谓同源是指,域名,协议, ...

  3. 【转】ajax 跨域 headers JavaScript ajax 跨域请求 +设置headers 实践

    解决跨域调用服务并设置headers 主要的解决方法需要通过服务器端设置响应头.正确响应options请求,正确设置 JavaScript端需要设置的headers信息 方能实现. 此处手札 供后人参 ...

  4. JavaScript(9)--- 跨域

    JavaScript(9)--- 跨域 一.跨域原理(同源策略) 在项目搭建的初期,因为现在项目基本上都是前后端分离,所以不可避免地会遇到跨域问题,而造成跨域的罪魁祸首就是浏览器的同源策略.所以要解决 ...

  5. jquery ajax跨域的完美解决方法(jsonp方式)

    ajax跨域请求的问题,JQuery对于Ajax的跨域请求有两类解决方案,不过都是只支持get方式,接下来为大家详细介绍下客户端JQuery.ajax的调用代码     今天在项目中需要做远程数据加载 ...

  6. 如何实现vue前端跨域,proxyTable解决开发环境前端跨域问题

    在开发环境与后端调试的时候难免会遇到跨域问题,很多人说跨域交给后端解决就好了. 其实不然,前端也有很多方法可以解决跨域,方便也快捷. 常见的有nginx转发.node代理. 在vue项目中常用的是pr ...

  7. AJAX跨域问题以及解决思路(更新中)

    跨域的三大原因(同时满足) 浏览器限制 跨域 XHR请求 解决思路: 让浏览器不做限制,指定参数,让浏览器不做校验,但该方法不太合理,它需要每个人都去做改动. 不要发出XHR请求,这样就算是跨域,浏览 ...

  8. 原生JavaScript实现跨域

    为什么需要跨域呢?这是因为我们一般的请求都是使用xhr的,但是它只能调用同一个域里面的接口,有时候,我们想要在自己的站点中调用其他站点的接口,这时候就要用到跨域了.其实,跨域并不难,我们可以通过Jav ...

  9. 解决ajax跨域问题的一种方法

    解决ajax跨域问题的一种方法 前后端分离经常用json来传输数据,比较常见的问题就有ajax跨域请求的错误问题,这里是我的一种解决方法: 在java中加入如下的注解类: import org.spr ...

随机推荐

  1. 第10篇 WINDOWS2003服务器 IIS上配置404页面的图文教程

    打开IIS 找到你的网站,点右键,选择属性 选择“自定义错误”标签页,找到404的那一项,点“编辑属性”按钮 (方案一)在“消息类型”里选“URL”,然后在下面的“URL”输入框里,填上你的404错误 ...

  2. vmware workstation 14 黑屏处理方法

    从12升级到14以后,所有老的虚拟系统全部黑屏.进行了一波操作,例如:虚拟机-管理-更改硬件兼容性,选择14.黑屏将加速3D图形勾选去掉:启动,关闭,再勾选上,启动.黑屏将显示器选择为指定监视器,黑屏 ...

  3. 【LeetCode】 -- 68.Text Justification

    题目大意:给定一个数组容器,里面存有很多string: 一个int maxWith.让你均匀安排每一行的字符串,能够尽可能的均匀. 解题思路:字符串+贪心.一开始想复杂了,总觉的题意描述的不是很清楚, ...

  4. Flume 是什么?

    Flume是一个分布式.可靠.和高可用的海量日志聚合的系统,支持在系统中定制各类数据发送方,用于收集数据:同时,Flume提供对数据进行简单处理,并写到各种数据接受方(可定制)的能力. 收集.聚合事件 ...

  5. hibernate annotation 生成uuid主键

    JPA标准方式下,不可以生成uuid类型的主键,但是hibernate提供了一些方式生成uuid主键,具体如下: 1.主键生成器     @GeneratedValue(generator=" ...

  6. 11、scala函数式编程

    1.将函数赋值给变量 2.匿名函数 3.高阶函数 4.高阶函数的类型推断 5.Scala的常用高级函数 6.闭包 7.SAM转换 8.Currying函数 9.return 1.将函数赋值给变量 Sc ...

  7. Build Tool-自动化构建工具

    输入:工程文件+编译说明文件: 处理:自动化构建工具+编译器: 输出:可执行文件. 相对于手动编译. Historically, build automation was accomplished t ...

  8. iOS crash log 解析 symbol address = stack address - slide 运行时获取slide的api 利用dwarfdump从dsym文件中得到symbol

    概述: 为什么 crash log 内 Exception Backtrace 部分的地址(stack address)不能从 dsym 文件中查出对应的代码? 因为 ASLR(Address spa ...

  9. Redis 之order set有序集合结构及命令详解

    1.zadd key score1 value1 score2 value2  添加元素 2.zrem key value1 value2 ..  删除集合中的元素 3.zremrangebyscor ...

  10. pandas写入多组数据到excel不同的sheet

    今天朋友问了我个需求,就是如何将多个分析后的结果,也就是多个DataFrame,写入同一个excel工作簿中呢? 之前我只写过放在一个sheet中,但是怎么放在多个sheet中呢?下面我在本地wind ...