2975

Mod注意:这个问题是关于为什么XMLHttpRequest/ fetch/等。浏览器上的受相同访问策略限制(您会收到提及 CORB 或 CORS 的错误),而 Postman 则不受此限制。这个问题不是关于如何修复“No 'Access-Control-Allow-Origin'...”错误。这是关于它们发生的原因。

请停止发帖


我正在尝试通过连接到RESTful API内置Flask来使用JavaScript进行授权。但是,当我提出请求时,我收到以下错误:

XMLHttpRequest 无法加载 http://myApiUrl/login。请求的资源上不存在“Access-Control-Allow-Origin”标头。因此,Origin 'null' 不允许访问。

我知道 API 或远程资源必须设置标头,但是为什么当我通过 Chrome 扩展Postman发出请求时它会起作用?

这是请求代码:

$.ajax({
  type: 'POST',
  dataType: 'text',
  url: api,
  username: 'user',
  password: 'pass',
  crossDomain: true,
  xhrFields: {
    withCredentials: true,
  },
})
  .done(function (data) {
    console.log('done');
  })
  .fail(function (xhr, textStatus, errorThrown) {
    alert(xhr.responseText);
    alert(textStatus);
  });
4

10 回答 10

1546

如果我理解正确,您正在对与您的页面所在的域不同的域执行XMLHttpRequest 。因此浏览器会阻止它,因为出于安全原因,它通常允许同一来源的请求。当您想要进行跨域请求时,您需要做一些不同的事情。有关如何实现这一点的教程是使用 CORS

当您使用 Postman 时,它们不受此政策的限制。引用自跨域 XMLHttpRequest

常规网页可以使用 XMLHttpRequest 对象从远程服务器发送和接收数据,但它们受到同源策略的限制。扩展并没有那么有限。扩展程序可以与其源之外的远程服务器通信,只要它首先请求跨域权限。

于 2013-11-17T19:49:53.533 回答
319

警告:使用Access-Control-Allow-Origin: *会使您的 API/网站容易受到跨站请求伪造(CSRF) 攻击。在使用此代码之前,请确保您了解风险。

如果您使用的是PHP,这很容易解决。只需在处理请求的 PHP 页面的开头添加以下脚本:

<?php header('Access-Control-Allow-Origin: *'); ?>

如果您使用的是Node-red ,则必须通过取消注释以下行来允许文件中的CORS :node-red/settings.js

// The following property can be used to configure cross-origin resource sharing
// in the HTTP nodes.
// See https://github.com/troygoode/node-cors#configuration-options for
// details on its contents. The following is a basic permissive set of options:
httpNodeCors: {
 origin: "*",
 methods: "GET,PUT,POST,DELETE"
},

如果您使用的Flask与问题相同;你必须先安装flask-cors

$ pip install -U flask-cors

然后在您的应用程序中包含 Flask cors。

from flask_cors import CORS

一个简单的应用程序将如下所示:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

@app.route("/")
def helloWorld():
  return "Hello, cross-origin-world!"

有关更多详细信息,您可以查看Flask 文档

于 2014-12-03T20:24:24.560 回答
93

因为
$.ajax({type: "POST" - 调用OPTIONS
$.post( - 调用POST

两者是不同的。邮递员正确地调用“POST”,但当我们调用它时,它将是“OPTIONS”。

对于 C# Web 服务 - Web API

请在 <system.webServer> 标签下的web.config文件中添加以下代码。这将起作用:

<httpProtocol>
    <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
    </customHeaders>
</httpProtocol>

请确保您在 Ajax 调用中没有犯任何错误

jQuery

$.ajax({
    url: 'http://mysite.microsoft.sample.xyz.com/api/mycall',
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
    },
    type: "POST", /* or type:"GET" or type:"PUT" */
    dataType: "json",
    data: {
    },
    success: function (result) {
        console.log(result);
    },
    error: function () {
        console.log("error");
    }
});

注意:如果您正在寻找从第三方网站下载内容,那么这对您没有帮助。您可以尝试以下代码,但不能尝试 JavaScript。

System.Net.WebClient wc = new System.Net.WebClient();
string str = wc.DownloadString("http://mysite.microsoft.sample.xyz.com/api/mycall");
于 2016-12-13T13:02:58.870 回答
38

深的

在以下作为 API 的调查中,我使用http://example.com而不是您的问题中的 http://myApiUrl/login,因为这是第一个工作。我假设您的页面位于http://my-site.local:8088上。

注意:API 和您的页面具有不同的域!

您看到不同结果的原因是 Postman:

  • 设置标头Host=example.com(您的 API)
  • 未设置标题Origin
  • Postman 实际上根本不使用您的网站网址(您只需在 Postman 中输入您的 API 地址) - 他只向 API 发送请求,因此他假设网站与 API 具有相同的地址(浏览器不假设这一点)

这类似于站点和 API 具有相同域时浏览器发送请求的方式(浏览器也设置了 header item Referer=http://my-site.local:8088,但是我在 Postman 中看不到它)。没有Origin设置header时,通常服务器默认允许此类请求。

在此处输入图像描述

这是 Postman 发送请求的标准方式。但是当您的站点和 API 具有不同的域时,浏览器会发送不同的请求,然后发生CORS并且浏览器会自动:

  • 设置标头Host=example.com(您的作为 API)
  • 设置标题Origin=http://my-site.local:8088(您的网站)

(标题Referer与 具有相同的值Origin)。现在在 Chrome 的控制台和网络选项卡中,您将看到:

在此处输入图像描述

在此处输入图像描述

当你有Host != Origin这个是 CORS,并且当服务器检测到这样的请求时,它通常会默认阻止它

Origin=null当您从本地目录打开 HTML 内容并发送请求时设置。同样的情况是当您<iframe>在. 您可以在此处找到有关此的更多信息。HostOrigin=null

fetch('http://example.com/api', {method: 'POST'});
Look on chrome-console > network tab

如果你不使用简单的 CORS 请求,通常浏览器会在发送主请求之前自动发送一个 OPTIONS 请求 - 更多信息在这里。下面的片段显示了它:

fetch('http://example.com/api', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json'}
});
Look in chrome-console -> network tab to 'api' request.
This is the OPTIONS request (the server does not allow sending a POST request)

您可以更改服务器的配置以允许 CORS 请求。

这是一个示例配置,它在 nginx (nginx.conf 文件)上打开CORS -always/"$http_origin"为 nginx 和Apache设置非常小心"*"- 这将解除对任何域的 CORS 的阻止(在生产中而不是星号使用您的具体页面地址,这会消耗您的接口)

location ~ ^/index\.php(/|$) {
   ...
    add_header 'Access-Control-Allow-Origin' "$http_origin" always;
    add_header 'Access-Control-Allow-Credentials' 'true' always;
    if ($request_method = OPTIONS) {
        add_header 'Access-Control-Allow-Origin' "$http_origin"; # DO NOT remove THIS LINES (doubled with outside 'if' above)
        add_header 'Access-Control-Allow-Credentials' 'true';
        add_header 'Access-Control-Max-Age' 1728000; # cache preflight value for 20 days
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'My-First-Header,My-Second-Header,Authorization,Content-Type,Accept,Origin';
        add_header 'Content-Length' 0;
        add_header 'Content-Type' 'text/plain charset=UTF-8';
        return 204;
    }
}

这是在 Apache 上打开CORS的示例配置(.htaccess 文件)

# ------------------------------------------------------------------------------
# | Cross-domain Ajax requests                                                 |
# ------------------------------------------------------------------------------

# Enable cross-origin Ajax requests.
# http://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity
# http://enable-cors.org/

# <IfModule mod_headers.c>
#    Header set Access-Control-Allow-Origin "*"
# </IfModule>

# Header set Header set Access-Control-Allow-Origin "*"
# Header always set Access-Control-Allow-Credentials "true"

Access-Control-Allow-Origin "http://your-page.com:80"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT"
Header always set Access-Control-Allow-Headers "My-First-Header,My-Second-Header,Authorization, content-type, csrf-token"

于 2019-12-16T09:06:06.353 回答
28

应用 CORS 限制是由服务器定义并由浏览器实现的安全功能。

浏览器查看服务器的 CORS 策略并尊重它。

但是,Postman 工具并不关心服务器的 CORS 策略。

这就是为什么 CORS 错误出现在浏览器中,而不是 Postman 中的原因。

于 2020-02-02T10:27:43.450 回答
24

您得到的错误是由于 CORS 标准造成的,该标准对 JavaScript 如何执行 ajax 请求设置了一些限制。

CORS 标准是在浏览器中实现的客户端标准。因此,阻止调用完成并生成错误消息的是浏览器,而不是服务器。

Postman 没有实现 CORS 限制,这就是为什么在从 Postman 发出相同调用时看不到相同错误的原因。

为什么Postman 不实施 CORS?CORS 定义了与发起请求的页面的来源(URL 域)相关的限制。但在 Postman 中,请求并非来自具有 URL 的页面,因此 CORS 不适用。

于 2021-01-09T21:37:06.437 回答
5

解决方案和问题起源

您正在向不同的域发出XMLHttpRequest,例如:

  1. 领域一:some-domain.com
  2. 领域二:some-different-domain.com

域名的这种差异触发了称为SOP(同源策略)的CORS跨域资源共享)策略,该策略强制在Ajax、XMLHttpRequest 和其他 HTTP 请求中使用相同的域(因此是Origin) 。

为什么当我通过 Chrome 扩展 Postman 发出请求时它会起作用?

客户端(大多数浏览器开发工具)可以选择强制执行同源策略。

大多数浏览器执行同源策略以防止与CSRF跨站点请求伪造)攻击相关的问题。

Postman作为开发工具选择不强制执行 SOP,而某些浏览器强制执行,这就是为什么您可以通过 Postman 发送您无法使用浏览器通过 JS 通过 XMLHttpRequest 发送的请求。

于 2022-01-03T11:36:07.120 回答
1

如果您的网关超时太短并且您正在访问的资源的处理时间比超时时间长,您也可能会收到此错误。这可能是复杂的数据库查询等的情况。因此,上面的错误代码可以掩盖这个问题。只需检查错误代码是否为 504 而不是 404,如上面的 Kamils 回答或其他内容。如果是 504,那么增加网关超时可能会解决问题。

在我的情况下,可以通过在 IE 浏览器中禁用同源策略 (CORS) 来消除 CORS 错误,请参阅如何禁用同源策略 Internet Explorer。执行此操作后,日志中出现纯 504 错误。

于 2021-12-09T12:34:24.367 回答
0

用于浏览器测试目的:Windows - 运行:

chrome.exe --user-data-dir="C://Chrome dev session" --disable-web-security
于 2022-01-10T12:28:36.797 回答
0

您的 IP 未列入白名单,因此您收到此错误。要求后端人员将您正在访问的服务的 IP 列入白名单 https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers

于 2022-02-14T01:29:15.327 回答