跨域资源共享 (CORS) 概念

IT技术 javascript jquery ajax cors
2021-03-17 21:55:36

我对跨域 JavaScript 的概念有疑问。

有服务器(例如 amazon.com),其中只有选定的域才能使用其网络服务。所以肯定的是,如果我尝试使用他们的服务,从我的本地,我不能。我在我的控制台上得到了这个

跨域请求被阻止:同源策略不允许在http://football20.myfantasyleague.com/2014/export?TYPE=rosters&L=52761&W=&JSON=0读取远程资源 这可以通过将资源移动到同一域或启用 CORS 来解决。

PS:我也使用jquery跨域方式,但没有用。

但是,如果在选定的域中使用亚马逊的网络服务的某个域具有 JavaScript,如果我们将其包含在我们的 html 中,它就可以工作。

<script src="http://example.com"></script>

他们有一种方法来获得 Ajax 的响应。

我的问题是:

  1. 当我们从 Internet url 引用 JavaScript 文件时会发生什么。我们的机器上有运行本地副本吗?
  2. 是否创建了 httpRequest,将有一个请求源作为我的域或 xyz。
4个回答

前面的重要说明:如果另一端的服务器没有启用它,则您无法在客户端代码中执行任何操作来允许跨域 ajax 请求。

在回答你的问题之前,让我先给你一个背景:

同源安全策略

简单地说,同源安全策略确保来自一个源的脚本可能不会从其他源获取内容。现在给大家解释起源的概念,我引用维基百科文章中同源安全策略的部分内容

下表概述了针对 URL“ http://www.example.com/dir/page.html进行检查的典型结果

Compared URL                                             Outcome  Reason
-------------------------------------------------------  -------  ----------------------
http://www.example.com/dir/page2.html                    Success  Same protocol and host
http://www.example.com/dir2/other.html                   Success  Same protocol and host
http://username:password@www.example.com/dir2/other.html Success  Same protocol and host
http://www.example.com:81/dir/other.html                 Failure  Same protocol and host but different port
https://www.example.com/dir/other.html                   Failure  Different protocol
http://en.example.com/dir/other.html                     Failure  Different host
http://example.com/dir/other.html                        Failure  Different host (exact match required)
http://v2.www.example.com/dir/other.html                 Failure  Different host (exact match required)
http://www.example.com:80/dir/other.html                 Depends  Port explicit. Depends on implementation in browser.

与其他浏览器不同,Internet Explorer 不会在源计算中包含端口,而是使用安全区域来代替。

因此,例如,您的 JavaScript 无法从 Web 服务器下载任何内容(也就是向其发出 HTTP 请求),而不是它源自的服务器。这正是您不能将 XmlHttpRequests(又名 AJAX)发送到其他域的原因。


CORS 是另一端的服务器(不是浏览器中的客户端代码)可以放宽同源策略的一种方式

关于跨域资源共享 (CORS)的过于简化的描述

CORS 标准通过添加新的 HTTP 标头来工作,这些标头允许服务器向允许的源域提供资源。浏览器支持这些标头并遵守它们建立的限制。

示例:假设您的站点是http://my-cool-site.com并且,您在域中有一个第三方 API http://third-party-site.com,您可以通过 AJAX 访问它。

假设来自您服务器的页面my-cool-site.comthird-party-site.com. 通常,用户浏览器会根据同源安全策略拒绝对您自己的域/子域以外的任何其他站点的 AJAX 调用但如果浏览器和第三方服务器支持 CORS,则会发生以下情况:

  • 浏览器将发送和OriginHTTP 标头到third-party-site.com

    Origin: http://my-cool-site.com
    
  • 如果第三方服务器接受来自您域的请求,它将以Access-Control-Allow-OriginHTTP 标头响应

    Access-Control-Allow-Origin: http://my-cool-site.com
    
  • 要允许所有域,第三方服务器可以发送此标头:

    Access-Control-Allow-Origin: *
    
  • 如果您的站点不被允许,浏览器将抛出错误。

如果客户端具有支持 CORS 的相当现代的浏览器,并且您的第三方服务器也支持 CORS,则 CORS 可能对您有用。

在一些过时的浏览器(例如 IE8)中,您必须使用 Microsoft 特定的XDomainRequest对象,而不是XMLHttpRequest使用 CORS 进行正确调用;现在已经过时了,所有现代浏览器(包括来自 Microsoft 的浏览器)都XMLHttpRequest改为处理 CORS 但是如果你需要支持过时的浏览器,这个页面是这样描述的:

要发出 CORS 请求,您只需XMLHttpRequest在 Firefox 3.5+、Safari 4+ 和 Chrome 中使用,并XDomainRequest在 IE8+ 中使用对象。使用XMLHttpRequest对象时,如果浏览器发现您正在尝试进行跨域请求,它将无缝触发 CORS 行为。

这是一个 javascript 函数,可帮助您创建跨浏览器 CORS 对象。

function createCORSRequest(method, url){
    var xhr = new XMLHttpRequest();
    if ("withCredentials" in xhr){
        // XHR has 'withCredentials' property only if it supports CORS
        xhr.open(method, url, true);
    } else if (typeof XDomainRequest != "undefined"){ // if IE use XDR
        xhr = new XDomainRequest();
        xhr.open(method, url);
    } else {
        xhr = null;
    }
    return xhr;
}

同样,这仅适用于过时的浏览器。


上述原因是您无法从脚本中使用 Amazon 网络服务的原因。并且亚马逊服务器将只允许将他们的 JavaScript 文件下载到从选定域提供的页面。

要回答您的编号问题:

    • 如果文件来自同一来源,则浏览器将下载该文件。
    • 如果它不在同一来源,则在 CORS 请求成功时将下载该文件。
    • 否则,下载脚本将失败。
    • 如果下载成功,JavaScript 文件的内容将被加载到浏览器的内存中,解释并执行。
  1. 请参阅 CORS 上的说明以了解。

CORS 是必须在服务器上修改的设置。它允许外部域请求网页上的资源。简单地更改客户端上的代码不会改变 CORS 的功能。

您可以从“脚本”标签内访问页面的原因是,标签的处理方式与跨源请求的所有其他数据不同。在过去,您可以使用将 JSON 数据存储在 HTML 标签内的 JSONP 将 CORS“破解”到您的系统上。

在 Apache 中启用 CORS:

首先通过键入找到您的 httpd.conf

ps -ef | grep apache

这将为您提供 Apache 的位置。找到该类型后:

 <apache-location> -V

这将返回您的 httpd.conf 的确切位置,如下所示:

 -D SERVER_CONFIG_FILE="/etc/apache2/apache2.conf"

现在您需要转到 httpd.conf 并输入“/”来搜索<directory>. 找到标签后,在它之后输入:

Header set Access-Control-Allow-Origin "*"

保存文件并通过运行确认语法正确:

apachectl -t

如果检查无误,请运行优雅重启命令:

apachectl -k graceful

服务器重新启动后,您的文件现在应该可以通过外部脚本访问了。

如果由于错误而无法保存配置,请尝试退出编辑器并键入:

sudo chmod 755 httpd.conf

这使所有者可以完全访问配置文件,但其他人只能读取和执行它(http://en.wikipedia.org/wiki/Chmod)。

要测试这些更改,请在外部服务器上创建一个新的 index.html 文件并使用以下内容加载它:

<!doctype html>
<html>
    <head>
    <title>TEST</title>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.18/angular.js"></script>
    <script src="http://code.jquery.com/jquery-1.11.1.js"></script>
    <!-- Insert Scripts & CSS Here -->
    <link rel="stylesheet" type="text/css" href="http://d1e24pw9mnwsl8.cloudfront.net/c/bootstrap/css/bootstrap.min.css">
    </head>

    <body>

        <script>
        jQuery.get('yourwebsite.com/file.csv', function(data) {
        document.write(data);
        });
        </script>

    </body>

</html>

结果输出应反映 yourwebsite.com/file.csv 上的实时数据源

如果加载该 html 页面显示没有输出,请在 Firefox 上按 f12 打开开发人员的控制台。您很可能会看到一个错误:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at yourwebsite.com/file.csv. This can be fixed by moving the resource to the same domain or enabling CORS.

这意味着要么 a) 您的 httpd.conf 配置不正确/未保存,要么 b) 您忘记重新启动 Web 服务器。

警告Access-Control-Allow-Origin "*"如果您的服务提供的数据不打算公开,则可能非常有害。
2021-04-30 21:55:36
你是对的。您还可以指定特定的网址:Access-Control-Allow-Origin: http://www.example-website.com
2021-05-02 21:55:36
我认为这对 OP 没有帮助,因为他希望能够sudo chmod 755 httpd.conf在亚马逊的服务器中使用。
2021-05-04 21:55:36

在 .htaccess 文件中,只需添加以下行:

Header set Access-Control-Allow-Origin *

这不是前端的问题,这是后端的问题。您应该在后端允许 CORS 来源。

我正在使用 Django。并添加 CORS 中间件并允许 CORS_ORIGINS 解决了这个问题。

添加 CORS 中间件

MIDDLEWARE = [
...
'corsheaders.middleware.CorsMiddleware',
...
]

并允许 CORS。您可以允许所有来源或仅允许特定来源。

CORS_ORIGIN_ALLOW_ALL = True

仅允许特定来源

CORS_ORIGIN_ALLOW_ALL = False

CORS_ORIGIN_WHITELIST = (
    '<YOUR_DOMAIN>[:PORT]',
)

一个例子 :

CORS_ORIGIN_ALLOW_ALL = False

CORS_ORIGIN_WHITELIST = (
    '127.0.0.1:3000', 'frontend.com',
)