跨域资源共享(CORS)概念

19

我对跨域JavaScript的概念有一个问题。

有一台服务器(例如amazon.com),只有特定的域名才能使用他们的网络服务。 因此,如果我试图从本地使用他们的服务,肯定是不行的。我在我的控制台中看到了以下信息:

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

附注:我也使用了jQuery的跨域方式,但没有成功。

但是,如果某个域名是被选中的域之一且可以使用亚马逊的网络服务,则该域名有一个JavaScript文件,如果我们在HTML中包含该文件,它将起作用。

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

他们有一种使用Ajax获取响应的方法。

我的问题是:

  1. 当我们从互联网URL引用JavaScript文件时会发生什么?我们是否拥有在本地运行的副本?
  2. 创建的httpRequest将具有请求源作为我的域或xyz吗?

4
Ajax请求的相关域是主页面所加载的域。通过<script>标签加载的JavaScript文件的URL没有影响。 - Pointy
4
当页面从<script>标签加载JavaScript时,实际上会获取该文件并在客户端上运行。 - Pointy
@Pointy:感谢回复,但是请求如何从他的方法获取响应?当我将相同的结构复制粘贴到我的本地时,它为什么不起作用?请解释一下。如果您有任何跨浏览器方面的参考资料,将不胜感激。 - Sashi Kant
如果有一个服务器配置允许来自某个域的请求,而你的域不是那个域,那么它将无法工作。服务器可以配置为允许来自任何域或某个特定域列表的请求。 - Pointy
这是后端的问题,对吧?这不是Javascript的问题。 - Trect
4个回答

48

重要提示:如果另一端的服务器没有启用,您无法在客户端代码中执行任何操作以允许跨源ajax请求。

在回答您的问题之前,让我先给您介绍一下背景:

同源安全策略

简而言之,同源安全策略确保来自一个源的脚本不能获取其他来源的内容。现在,为了向您解释“源”的概念,让我引用Wikipedia Same-Origin Security Policy文章的部分内容:

The following table gives an overview of typical outcomes for checks against the 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.

Unlike other browsers, Internet Explorer does not include the port in the calculation of the origin, using the Security Zone in its place.

因此,例如,您的JavaScript不能从其他服务器下载任何内容(也就是说,向Web服务器发出HTTP请求)。这正是为什么您无法对其他域进行XmlHttpRequests(也称为AJAX)的原因。
CORS是服务器端(而非浏览器中的客户端代码)可以放宽同源策略的一种方式。 跨域资源共享(CORS)的简单描述:
引用块: CORS标准通过添加新的HTTP头来允许服务器向允许的源域提供资源。浏览器支持这些头并遵守它们所建立的限制。
示例:假设您的网站是http://my-cool-site.com,并且您有一个第三方API在域http://third-party-site.com上,您可以通过AJAX访问它。
假设来自您的服务器my-cool-site.com的页面向third-party-site.com发出请求。通常情况下,用户的浏览器会拒绝对除自己的域/子域之外的任何其他站点的AJAX调用,根据同源安全策略。但如果浏览器和第三方服务器支持CORS,则会发生以下事情:
  • Browser will send and Origin HTTP header to third-party-site.com

    Origin: http://my-cool-site.com
    
  • If the third party server accepts requests from your domain, it will respond with an Access-Control-Allow-Origin HTTP header:

    Access-Control-Allow-Origin: http://my-cool-site.com
    
  • To allow all domains, third party server can send this header:

    Access-Control-Allow-Origin: *
    
  • If your site is not allowed, browser will throw an error.

如果客户端使用 支持CORS的现代浏览器,并且你的第三方服务器也支持CORS,那么CORS对你很有用。

在一些过时的浏览器中(例如IE8),你必须使用Microsoft特定的XDomainRequest对象来替代XMLHttpRequest,以便能够正确地使用CORS进行调用;不过这已经过时了,所有现代浏览器(包括微软的浏览器)都将CORS处理为XMLHttpRequest。但如果你需要支持过时的浏览器,该页面描述了如何实现它:

To make a CORS request you simply use XMLHttpRequest in Firefox 3.5+, Safari 4+ and Chrome and XDomainRequest object in IE8+. When using XMLHttpRequest object, if the browser sees that you are trying to make a cross-domain request it will seamlessly trigger CORS behaviour.

Here is a javascript function that helps you create a cross browser CORS object.

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;
}

再次强调,这仅适用于过时的浏览器。


上述原因是为什么你不能从脚本中使用亚马逊的网络服务。亚马逊服务器只允许从选定的域名提供的页面下载其JavaScript文件。
回答您的编号问题:
1. 如果文件与当前源相同,则浏览器将下载该文件。 2. 如果不在同一源中,则如果CORS请求成功,文件将被下载。 3. 否则,下载脚本将失败。 4. 如果下载成功,则JavaScript文件的内容将加载到浏览器的内存中进行解释和执行。
有关CORS的说明,请参见描述。

4
CORS是必须在服务器上修改的设置。它允许外部域请求网页上的资源。仅仅改变客户端代码不会改变CORS的功能。之所以可以通过“script”标签访问页面,是因为标签在跨源请求中与所有其他数据处理方式不同。在旧时代,您可以使用JSONP将JSON数据存储在HTML标签中来“黑客”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.

这意味着你的httpd.conf配置不正确/未保存,或者你忘记重新启动Web服务器。

1
警告:如果您的服务提供的数据不是公开的,**Access-Control-Allow-Origin "*"** 可能会非常有害。 - sampathsris
你是正确的。你也可以指定特定的URL:Access-Control-Allow-Origin: http://www.example-website.com - Andrew
我认为这对OP没有帮助,因为他无法在Amazon的服务器上执行“sudo chmod 755 httpd.conf”。 - sampathsris

2
在 .htaccess 文件中,只需添加这行代码:
Header set Access-Control-Allow-Origin *

0

这不是前端的问题,而是后端的问题。您应该允许后端的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',
)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接