为啥我的 JavaScript 代码会收到“请求的资源上不存在 'Access-Control-Allow-Origin' 标头”错误,而 Postman 却没有?

Posted

技术标签:

【中文标题】为啥我的 JavaScript 代码会收到“请求的资源上不存在 \'Access-Control-Allow-Origin\' 标头”错误,而 Postman 却没有?【英文标题】:Why does my JavaScript code receive a "No 'Access-Control-Allow-Origin' header is present on the requested resource" error, while Postman does not?为什么我的 JavaScript 代码会收到“请求的资源上不存在 'Access-Control-Allow-Origin' 标头”错误,而 Postman 却没有? 【发布时间】:2013-11-17 19:29:06 【问题描述】:

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

请停止发帖

适用于所有语言/框架的 CORS 配置。而是find your relevant language/framework's question。 允许请求绕过 CORS 的第三方服务 用于为各种浏览器关闭 CORS 的命令行选项

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

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

我知道API或远程资源必须设置header,但是为什么当我通过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);
  );

【问题讨论】:

你是从localhost做请求还是直接执行html @MD.SahibBinMahboob 如果我理解您的问题,我会向本地主机请求 - 我的计算机上有页面并运行它。当我在托管上部署站点时,它给出了相同的结果。 你执行页面的域和请求的域名是相同还是不同? 对于任何寻求更多阅读的人,MDN 有一篇关于 ajax 和跨源请求的好文章:developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS 这个问题的答案(现已删除,仅对 10K'ers 可见)是元问题 Why was this upvoted answer deleted once, and deleted again when reposted? 的主题 【参考方案1】:

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

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

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

【讨论】:

浏览器没有阻塞请求。唯一完全阻止跨域 ajax 请求的浏览器是 IE7 或更早版本。所有浏览器,除了 IE7 和更早版本,都实现了 CORS 规范(部分 IE8 和 IE9)。您需要做的就是通过根据请求返回正确的标头来选择加入 API 服务器上的 CORS 请求。您应该在 mzl.la/VOFrSz 阅读 CORS 概念。 Postman 也通过 XHR 发送请求。如果您在使用邮递员时没有看到同样的问题,这意味着您在不知不觉中没有通过邮递员发送相同的请求。 @MD.SahibBinMahboob 邮递员没有“从您的 java/python”代码发送请求。它直接从浏览器发送请求。 XHR in Chrome extensions does work a bit differently, especially when cross-origin requests are involved.【参考方案2】:

警告:使用Access-Control-Allow-Origin: * 会使您的API/网站容易受到cross-site request forgery (CSRF) 攻击。在使用此代码之前,请确保您 understand the risks。

如果你使用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 documentation。

【讨论】:

您不应该关闭 CORS,因为您不知道它的用途。这会使您的用户处于根本不安全的状态。 尽管它可能不安全,但问题不在于安全性,而在于如何完成任务。这是开发人员在处理跨域 AJAX 请求时必须选择的选项之一。它帮助我解决了这个问题,对于我的应用程序,我不在乎数据来自哪里。我在目标域上使用 PHP 清理所有输入,所以,如果有人想向它发布一些垃圾,让他们试试。这里的要点是,可以从目标域允许跨域 AJAX。为答案 +1。 @meagar 同意您的观点,我们不应该启用 CORS,但有时我们需要在开发应用程序时对其进行测试,为此,最简单的方法是启用 CORS 并检查是否一切正常美好的。很多时候,前端开发人员无法访问后端系统,他们无法在后端系统中进行更改,或者他们需要为此编写代理。添加用于开发目的的关闭 CORS 的 chrome 扩展的最佳方法,如已删除的答案中所述。 如果在 php.ini 中使用 header() 脚本,如果答案(或顶部带有 WARNING 的编辑)能够向谁解释有风险,那应该会很有帮助。这里的问题是关于一个我们无法控制的外部站点,它只允许我们从浏览器导航和查看它,而如果我们需要从我们的服务器访问资源,它会启动 CORS 保护(不让我们每秒查询太多)。因此,我的问题仍然存在,如果在我们的服务器中使用 header() 脚本,我们的访问者会有什么危险?编辑是否将访客(我们)与主持人混淆了? @Eve CORS 保护与每秒的查询数量无关!它拒绝任何其他网站使用您的资源服务或页面。该警告已经包含两个链接来解释什么是风险【参考方案3】:

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

两者是不同的。 Postman 正确调用“POST”,但是当我们调用它时,它会是“OPTIONS”。

对于 C# 网络服务 - Web API

请在 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");

【讨论】:

【参考方案4】:

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

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

你看到不同结果的原因是邮递员:

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

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

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

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

(标头RefererOrigin 具有相同的值)。现在在 Chrome 的 Console & Networks 标签中,您将看到:

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

Origin=null 在您从本地目录打开 HTML 内容并发送请求时设置。同样的情况是当您在&lt;iframe&gt; 中发送请求时,就像在下面的 sn-p 中一样(但这里根本没有设置 Host 标头) - 通常,在 HTML 规范中提到不透明来源的任何地方,您都可以将其翻译为Origin=null。有关这方面的更多信息,您可以找到here。

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

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

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 请求。

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

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;
    

这是一个打开 CORS on Apache 的示例配置(.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"

【讨论】:

很好很好的解释,很容易赶上!谢谢你!【参考方案5】:

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

浏览器查看服务器的 CORS 策略并遵守它。

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

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

【讨论】:

【参考方案6】:

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

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

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

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

【讨论】:

@MrJedi:接受的答案没有解释为什么请求在 Postman 中成功,这是最初的问题。 服务器最初的目的是向客户端(浏览器软件程序)发送流,而不是向各种桌面或服务器应用程序发送流,而是以扭曲的方式运行。浏览器与服务器建立握手协议,收到关于连接的确认,然后数据流恢复。在某些 (DDOS) 情况下,机器人场服务器发送了数百万个查询,并且主机向这些停滞的连接中的每一个提交了许多资源(打开的进程),这些连接最终从未发生过 - 从而阻止了它回答其他合法请求的能力【参考方案7】:

解决方案和问题来源

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

    域一:some-domain.com 域二:some-different-domain.com

域名的这种差异触发了名为 SOP (Same-Origin Policy) 的 CORS (Cross-Origin Resource Sharing) 策略,该策略强制使用相同的域(因此 Origin ) 在Ajax、XMLHttpRequest 和其他 HTTP 请求中。

为什么当我通过 Chrome 扩展程序发出请求时它起作用了 邮递员?

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

大多数浏览器都会执行同源策略以防止与 CSRF (Cross-Site Request Forgery) 攻击相关的问题。

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

【讨论】:

【参考方案8】:

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

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

【讨论】:

如果你得到超时,你不会得到 CORS 错误 好吧,我在对系统进行故障排除时遇到了 CORS 错误,这让我大吃一惊,只是超时太短,导致连接关闭。增加超时时间后,系统表现完美。所以是的,超时导致了 No 'Access-Control-Allow-Origin' 错误,这让我首先进入了这个线程。因此,这可能对其与 504 一起抛出的其他人有所帮助。 这意味着您的应用配置存在错误。您不应该在超时时收到此错误【参考方案9】:

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

chrome.exe --user-data-dir="C://Chrome dev session" --disable-web-security

【讨论】:

【参考方案10】:

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

【讨论】:

以上是关于为啥我的 JavaScript 代码会收到“请求的资源上不存在 'Access-Control-Allow-Origin' 标头”错误,而 Postman 却没有?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的 JavaScript 代码会收到“请求的资源上不存在 'Access-Control-Allow-Origin' 标头”错误,而 Postman 却没有?

为啥我的 JavaScript 代码会收到“请求的资源上不存在 'Access-Control-Allow-Origin' 标头”错误,而 Postman 却没有?

为啥我的 JavaScript 代码会收到“请求的资源上不存在 'Access-Control-Allow-Origin' 标头”错误,而 Postman 却没有?

为啥我的 JavaScript 代码会收到“请求的资源上不存在 'Access-Control-Allow-Origin' 标头”错误,而 Postman 却没有?

为啥我的 JavaScript 代码会收到“请求的资源上不存在 'Access-Control-Allow-Origin' 标头”错误,而 Postman 却没有?

为啥我的 JavaScript 代码会收到“请求的资源上不存在 'Access-Control-Allow-Origin' 标头”错误,而 Postman 却没有?