对远程站点的本地 AJAX 调用在 Safari 中有效,但在其他浏览器中无效

Posted

技术标签:

【中文标题】对远程站点的本地 AJAX 调用在 Safari 中有效,但在其他浏览器中无效【英文标题】:local AJAX-call to remote site works in Safari but not in other browsers 【发布时间】:2015-07-08 23:11:31 【问题描述】:

我正在维护一个使用 javascript 的网站。该脚本使用 jQuery 并从通常托管该站点的服务器加载一些内容。

为了方便维护站点,我在 iMac 上运行站点的本地副本。当我使用 Safari 时,这工作得很好。但是 Firefox、Opera 和 Chrome 拒绝工作。我想这是因为跨域策略。 (我无法用 IE 进行测试,因为 IE 必须在我的 iMac 上的虚拟机中运行,因此无法访问任何本地文件)

在 Firefox 和其他浏览器中是否有一个设置,我可以告诉浏览器可以使用本地 javascript 从本地 html 页面 ajax 加载位于远程服务器上的文件?

简而言之:这是我的 html 页面:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>some title</title>
        <link rel="stylesheet" type="text/css" href="../css/stylesheet.css">
        <script src="../js/jquery-2.1.3.min.js"></script>
        <script src="../js/myScript.js"></script>
    </head>
    <body>
        <!-- some content with a div-container to receive the ajax-content -->
    </body>
</html>

这是 myScript.js:

var errorMsg = function (msg) 
    //insert the message into the html-page
;

var JSONerror = function (jqXHR, textStatus, errorThrown ) 
    var msg = 'JSON-answer: '+jqXHR.responseText;
    msg += '<br>'+'JSON-Errorstatus: '+textStatus;
    if ($.type(errorThrown) === 'string') 
        msg += '<br>'+'Error: '+errorThrown;
    
    errorMsg(msg);
;

var JSONreceive = function (JSONobj, StatusString, jqXHR) 
    //insert the data in JSONobj into the html-page


var StartAJAX = function () 
    $.ajax(
        url: 'http://my.domain.tld/cgi-bin/myPerlScript.pl',
        data: "lastID=" + lastID
           + '&qkz=' + Math.random(),
           dataType: "json",
           success: JSONreceive,
           error: JSONerror
    );
;

还有一个事件监听器,它监听页面滚动和调整大小并检查其他一些约束(例如:是否已经有一个 ajax 调用在进行中?)。此侦听器调用StartAJAX

当它在 Safari 中我的页面的本地副本 (file:///User/...) 上调用 StartAJAX 时,我将 Ajax 内容完美地插入到我的 html 文档中。在其他浏览器中,我将错误消息插入到 html 页面中。它是:

JSON-答案:未定义 JSON-错误状态:错误 错误:

为什么它在 Safari 中有效,而在 Firefox、Chrome 和 Opera 中无效?

如何使这些浏览器正常工作?

(我需要在所有浏览器上测试它,因为所有浏览器都以不同的方式呈现相同的html-domument,但我不想在每次更改后将所有文件上传到服务器只是为了测试它。)

编辑:

看了一些答案,我想澄清一点,我显然没有说清楚:

我正在网络浏览器中搜索设置

    我不会更改我的远程网络服务器 (Apache) 的设置 我不会操作远程计算机上的任何文件 (.htaccess) 我不会在本地 iMac 上设置网络服务器 我不会在我的 Javascript 文件中更改 AJAX 调用的代码 我不会更改远程服务器上 Perl 脚本的代码

我可以告诉你原因:

我只是做一个简短的维护,我懒得在编辑后将每个操作过的文件上传到远程机器。网络服务器的设置适合​​实际操作。我不想更改它们(并且可能在完成工作之前忘记更改)。脚本也是如此:你们中的一些人想要更改的那些部分现在可以正常工作。没有理由接触 Ajax-Calls,因为它们在生产环境中没有任何问题。

我只想让那些愚蠢的浏览器 Firefox、Opera 和 Chrome 表现得像 Safari 并正确处理 Ajax 调用。

顺便说一句:

请任何人解释一下在 Firefox、Opera 或 Chrome 中通过 Ajax 从其他域调用数据的风险如此之大,而在 Safari 中做同样的事情似乎是无害的?

【问题讨论】:

根据您的编辑,您不愿意接受任何答案,尽管它们是正确的。每个浏览器都有浏览器限制。如果您想让 Firefox、Chrome 和 Opera 像 Safari 一样运行,您需要联系这些浏览器的制造商并请求​​添加您需要的功能。此外,还提供了几个解决 CORS 问题的选项以及参考资料,以便您可以了解有关 AJAX 调用如何跨不同域工作的更多信息。这里没有任何人可以改变浏览器的设计方式。 @Rob:你的答案是目前最有可能赢得赏金的人。但赏金今天并没有结束。 3天结束,浏览量不到60次。这给了我 3 天的时间来希望另外 60 人阅读我的问题,并且其中一个人能找到更好的答案。如果在 3 天内没有答案告诉我如何操作浏览器以便它们根据需要执行 ajax 调用,那么我将接受您的回答。所以请耐心等待! 【参考方案1】:

有一个plugin for chrome 会强制它忽略安全策略。您也可以使用flags 执行此操作。请注意,请不要在启用此功能的情况下浏览“真实网络”,因为这会给您的计算机带来安全风险。

火狐

This thread 表示目前在 Firefox 中没有办法做到这一点。

歌剧

同样,似乎没有内置方法可以忽略 CORS 策略。

替代方法是让服务器 (http://my.domain.tld) 在您的情况下返回正确的标头 - 特别是 Access-Control-Allow-Origin:

【讨论】:

我不明白为什么这在 Chrome、Firefox 和 Opera 中存在安全风险,而在 Safari 中却没有?它在 Safari 中运行良好。 它在 safari 中工作的原因是因为 safari 忽略了 file: 方案的 CORS 策略,如果您要在本地服务器下运行并浏览到 localhost 以查看您的站点(并使您的请求my.domain.tld),它也会在 safari 中被阻止 - 请参阅 ***.com/a/27117909/430231 了解其他人对此主题所做的研究。 你可以用 --disable-web-security 标志启动 chrome【参考方案2】:

为避免此问题,您应该使用网络服务器(如 apache、nginx、...)开发您的页面(在本地计算机上没问题),因此,您的 url ajax 调用以协议 http 或 https 开头,而不是“文件”。 “文件”是文件的路径,但使用的是 SO 路径系统,而不是 Web 服务器系统。

另一方面,浏览器具有“同源策略”。这是一项安全功能,但使用 ajax 调用进行 Web 开发的“问题”是什么?好吧,你的 ajax 调用总是在同一个服务器上完成,例如,如果你的网站在域“http://my-domain.com”上,那么你的 ajax 调用必须在同一个域“http://my-domain.com”上。

要在 ajax 调用中“绕过”SOP,您有三种解决方案:

在您的“my-domain.com”上创建一个代理,使用 curl(例如在 php 中)检索数据并将其返回给您的 ajax 调用 使用 JSON-P 允许您的域在您的网络服务器(例如 .htaccess)中为 CORS 设置正确的配置:http://enable-cors.org/

顺便说一句

我将回答:“请任何人解释通过 Ajax 从其他域调用数据的风险如此之大”。 (从 Mozilla MDN https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy 复制粘贴)

同源策略限制如何从 一个来源可以与另一个来源的资源交互。 同源策略被用作防止某些 跨站点请求伪造攻击。

【讨论】:

我的 ajax 调用不以“file:///”开头,它们以“http://”开头。它是以“file:///”开头的网站。通常,我的 html 文档位于从浏览器接收 Ajax-Call 的同一远程服务器上。刚才,为了维护,我在本地机器上有一个 html 文件的操纵副本。 Ajax 调用仍会转到远程服务器,这在 Safari 中没有问题,但在所有其他浏览器中。 好的,所以,可能是一个 cors 问题,因为协议更改:“file”!==“http”。如果您的 web 服务调用转到远程服务器,那么您需要在服务器上添加 cors 支持。 我的问题是,我无法想象任何对任何人都有害的“跨站点请求伪造攻击”。如果你知道一些例子,请回答这个问题(我写的):***.com/questions/30108066/…【参考方案3】:

由于相同的来源政策,您通常无法从不同的域请求资源。尝试将 crossDomain: true 添加到您的 AJAX 请求中,因为您正在尝试向其他域发出请求。

$.ajax(
    url: 'http://my.domain.tld/cgi-bin/myPerlScript.pl',
    crossDomain: true,
    data: "lastID=" + lastID
       + '&qkz=' + Math.random(),
       dataType: "json",
       success: JSONreceive,
       error: JSONerror
);

【讨论】:

不,我不会更改在生产条件下完美运行的 Ajax 调用。我想更改浏览器中的一些设置,使其在本地计算机上维护文档期间接受来自远程服务器的数据。【参考方案4】:

假设网站是域 A,而 perl 脚本位于域 B,您有两种选择: 1) 在域 B 的 Web 服务器上启用 CORS。http://enable-cors.org/ 2) 在域 A 上创建一个脚本(php、perl、ashx 等),调用域 B 上的脚本。域 A 上的脚本将充当代理,并且所有 Web 浏览器都允许。

【讨论】:

抱歉,您没有理解问题所在。一切都在同一个域上的正常条件下。所以没有理由改变服务器上的任何东西。当我因为维护而将 html 文档下载到本地 iMac 并将此本地文件加载到我的浏览器中时,才会出现问题。然后除 Safari 之外的所有浏览器都拒绝正确处理 Ajax 调用。在这种情况下,该网站不属于任何域。它是本地的。您的回答可能有助于解决其他一些问题,但不是我在问题中描述的问题。所以-1分。对不起。 你是对的。我确实假设当您说您正在运行网站的“本地”副本时,您确实是在“本地”Web 服务器上而不是从文件系统中运行它。那是对的吗?查看页面时,地址栏中显示的 url 是什么? 请仔细阅读我的问题。您要求的信息自 4 月底以来一直存在。 祝你好运。 由于浏览器安全..只允许处理不安全的网站

以上是关于对远程站点的本地 AJAX 调用在 Safari 中有效,但在其他浏览器中无效的主要内容,如果未能解决你的问题,请参考以下文章

Safari 5.1 基本身份验证注销问题

C# web页面 调用本地的mstsc.exe(远程桌面)?

跨域 Ajax 调用在 Safari 4 和 Safari 5 中不起作用

.ajax 在 IE 中不起作用 [重复]

本地加载 XML 的 jQuery Ajax 问题 - Safari 版本 11.0 - 错误:XMLHttpRequest 无法加载 .xml。预检响应不成功

Safari错误。 Javascript ajax json对象 - 无法获取属性。对象可能不再存在