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

2024-11-02 20:48:00
admin
原创
35
摘要:问题描述:Mod 注:这个问题是关于为什么浏览器上的XMLHttpRequest/ fetch/etc. 受到相同的访问策略限制(您会收到提及 CORB 或 CORS 的错误),而 Postman 却不受限制。这个问题不是关于如何修复“无‘Access-Control-Allow-Origin’...”错误。...

问题描述:

Mod 注:这个问题是关于为什么浏览器上的XMLHttpRequest/ fetch/etc. 受到相同的访问策略限制(您会收到提及 CORB 或 CORS 的错误),而 Postman 却不受限制。这个问题不是关于如何修复“无‘Access-Control-Allow-Origin’...”错误。而是关于为什么会发生这种情况。

请停止发帖

  • 世界上所有语言/框架的 CORS 配置。请查找相关语言/框架的问题。

  • 允许请求规避 CORS 的第三方服务

  • 用于关闭各种浏览器的 CORS 的命令行选项


我正在尝试通过连接到Flask内置的RESTfulAPI使用JavaScript进行授权。 但是,当我发出请求时,出现以下错误:

XMLHttpRequest cannot load http://myApiUrl/login. 
No 'Access-Control-Allow-Origin' header is present on the requested resource. 
Origin 'null' is therefore not allowed access.

我知道 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);
  });

解决方案 1:

如果我理解正确的话,你正在向与页面所在域不同的域执行XMLHttpRequest。因此浏览器会阻止它,因为出于安全原因,它通常允许来自同一来源的请求。当您想要执行跨域请求时,您需要做一些不同的事情。

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

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

解决方案 2:

警告:使用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 文档。

解决方案 3:

因为

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

$.post( - 调用POST

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

对于 C# Web 服务 - Web API

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

&lt;httpProtocol>
    &lt;customHeaders>
        &lt;add name=&quot;Access-Control-Allow-Origin&quot; value=&quot;*&quot; />
    &lt;/customHeaders>
&lt;/httpProtocol>

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

jQuery

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

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

System.Net.WebClient wc = new System.Net.WebClient();
string str = wc.DownloadString(&quot;http://mysite.microsoft.sample.xyz.com/api/mycall&quot;);

解决方案 4:

深的

在下面的 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 内容时,会设置该请求,并发送请求。当您在 内发送请求时&lt;iframe>,情况也一样,如下面的代码片段所示(但此处Host根本没有设置标头) - 通常,HTML 规范中提到不透明来源的地方,您都可以将其转换为。您可以在此处Origin=null找到有关此内容的更多信息。

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

运行代码片段Hide results展开片段

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

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

运行代码片段Hide results展开片段

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

下面是在 nginx 上启用 CORS 的示例配置(nginx.conf 文件) - 在设置always/&quot;$http_origin&quot;nginx 和Apache 时要非常小心&quot;*&quot;- 这将解除对任何域的 CORS 阻止(在生产中,使用消耗 api 的具体页面地址而不是星号)

显示代码片段

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

Run code snippetHide resultsExpand snippet

以下是在 Apache 上启用 CORS 的示例配置(.htaccess 文件)

显示代码片段

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

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

# &lt;IfModule mod_headers.c>
#    Header set Access-Control-Allow-Origin &quot;*&quot;
# &lt;/IfModule>

# Header set Header set Access-Control-Allow-Origin &quot;*&quot;
# Header always set Access-Control-Allow-Credentials &quot;true&quot;

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

Run code snippetHide resultsExpand snippet

解决方案 5:

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

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

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

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

解决方案 6:

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

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

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

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

解决方案 7:

解决方案和问题起源

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

  1. 域一:some-domain.com

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

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

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

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

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

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

解决方案 8:

对于浏览器测试目的:

Windows——运行:

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

上述命令将禁用 chrome web 安全。因此,例如,如果您在本地项目上工作并在尝试发出请求时遇到 CORS 策略问题,则可以使用上述命令跳过此类错误。基本上,它将打开一个新的 chrome 会话。

解决方案 9:

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

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

解决方案 10:

要解决此问题,请在后端使用的doGet()或函数中写入此行代码doPost()

response.setHeader(&quot;Access-Control-Allow-Origin&quot;, &quot;*&quot;);

您可以输入访问该网站的网站或 API URL 端点,否则&quot;*&quot;它将是公开的。

解决方案 11:

您的 IP 地址未列入白名单,因此出现此错误。请让后端工作人员将您的 IP 地址列入白名单,以供您访问服务。

访问控制允许标头

解决方案 12:

对我来说,我因为不同的原因遇到此问题,远程域被添加到原点,部署的应用程序运行完美,除了一个端点我遇到了这个问题:

Origin https://mai-frontend.vercel.app is not allowed by Access-Control-Allow-Origin. Status code: 500

Fetch API cannot load https://sciigo.herokuapp.com/recommendations/recommendationsByUser/8f1bb29e-8ce6-4df2-b138-ffe53650dbab due to access control checks.

我发现我的 Heroku 数据库表不包含我的本地表的所有列,更新 Heroku 数据库表后一切正常。

解决方案 13:

您可以通过在服务器的web.config文件中添加以下脚本来允许CORS

&lt;system.webServer>
     &lt;httpProtocol>
         &lt;customHeaders>
            &lt;add name=&quot;Access-Control-Allow-Origin&quot; value=&quot;*&quot; />
            &lt;add name=&quot;Access-Control-Allow-Methods&quot; value=&quot;*&quot; />
            &lt;add name=&quot;Access-Control-Allow-Headers&quot; value=&quot;*&quot; />
         &lt;/customHeaders>
     &lt;/httpProtocol>
&lt;/system.webServer>

解决方案 14:

对我来说,我只需更换浏览器,它就可以正常工作。我当时在 localhost 上工作。我的 API 在 localhost:7133 上,我的应用程序在 localhost:5173 上。在 Chrome 和 Edge 中,它不起作用,但当我尝试使用 Opera 时,它起作用了。我认为当我在不同的域上发布 API 和 Web 应用程序时,这将是一个解决方案。

解决方案 15:

我们的问题是ModSecurity在 nginx 上触发的。请求从未到达 PHP 服务器,并向 Google Chrome 返回 403;由于我们有两个不同的域(原域和目标域),因此 Chrome 认为缺少 CORSAccess-Control-Allow-Origin是 CORS 问题。

解决方案是将请求编码为 base64 或更新 nginx 上的 ModSecurity 设置以不再阻止该请求。

解决方案 16:

如果你使用 Node.js(Express.js)构建后端,请尝试使用
npm i cors

....
const cors = require(&quot;cors&quot;);
.....

app.use(cors());
...

解决方案 17:

它通过在全球范围内应用这个中间件来为我工作:

&lt;?php

    namespace AppHttpMiddleware;

    use Closure;

    class Cors {
       public function handle($request, Closure $next) {
           return $next($request)
                   ->header(&#039;Access-Control-Allow-Origin&#039;, &#039;*&#039;)
                   ->header(&#039;Access-Control-Allow-Methods&#039;, &#039;GET, POST, PUT, DELETE, OPTIONS&#039;)
                   ->header(&#039;Access-Control-Allow-Headers&#039;, &quot;Accept,authorization,Authorization, Content-Type&quot;);
       }
    }
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用