XMLHttpRequest 无法加载 XXX 无‘Access-Control-Allow-Origin’标头

2024-11-02 21:00:00
admin
原创
33
摘要:问题描述:关于同源策略我有一个 Grunt 进程,它启动了 express.js 服务器的一个实例。它一直运行良好,直到现在它开始提供一个空白页,并在 Chrome(最新版本)的开发人员控制台中的错误日志中出现以下内容:XMLHttpRequest 无法加载https://www.example.com/ 请...

问题描述:

关于同源策略

我有一个 Grunt 进程,它启动了 express.js 服务器的一个实例。它一直运行良好,直到现在它开始提供一个空白页,并在 Chrome(最新版本)的开发人员控制台中的错误日志中出现以下内容:

XMLHttpRequest 无法加载https://www.example.com/
请求的资源上不存在“Access-Control-Allow-Origin”标头。因此不允许访问来源“ http://localhost:4300 ”。

什么原因阻止我访问该页面?


解决方案 1:

tl;dr — 当您想要使用客户端 JS 从不同的服务器读取数据时,您需要拥有数据的服务器向需要该数据的代码授予明确的权限。

最后有总结,答案中有标题,方便查找相关部分。建议阅读所有内容,因为它提供了有用的背景知识,有助于理解原因,从而更容易理解在不同情况下如何应用方法。

关于同源策略

这就是同源策略。这是浏览器实现的一个安全功能。

您的具体情况展示了它是如何为 XMLHttpRequest 实现的(如果您使用 fetch,您将获得相同的结果),但它也适用于其他事物(例如加载到 上的图像<canvas>或加载到 中的文档<iframe>),只是实现略有不同。

证明需要 SOP 的标准场景可以用三个字符来证明:

  • Alice 是一个有网络浏览器的人

  • Bob 经营着一个网站(https://www.example.com/在你的例子中)

  • Mallory 经营着一个网站(http://localhost:4300在您的例子中)

Alice 登录了 Bob 的网站,那里有一些机密数据。可能是公司内部网(只能通过 LAN 上的浏览​​器访问),或者是她的网上银行(只能通过输入用户名和密码后获得的 cookie 访问)。

Alice 访问 Mallory 的网站,该网站包含一些 JavaScript,这会导致 Alice 的浏览器向 Bob 的网站发出 HTTP 请求(从她的 IP 地址使用她的 cookie 等)。这可能就像使用XMLHttpRequest和阅读一样简单responseText

浏览器的同源策略阻止 JavaScript 读取 Bob 网站返回的数据(Bob 和 Alice 不希望 Mallory 访问这些数据)。(请注意,例如,您可以使用<img>跨源元素显示图像,因为图像的内容不会暴露给 JavaScript(或 Mallory)……除非您将 Canvas 混入其中,在这种情况下您生成同源违规错误)。


为什么你认为不应该应用同源策略

对于任何给定的 URL,可能不需要 SOP。以下是一些常见的情况:

  • Alice、Bob 和 Mallory 是同一个人。

  • Bob 提供的是完全公开的信息

…但浏览器无法知道上述任何一种情况是否属实,因此信任不是自动的,并且会应用 SOP。必须明确授予许可,浏览器才会将从 Bob 收到的数据提供给其他网站。


为什么同源策略只适用于网页中的 JavaScript,而不适用于其他内容

网页之外

浏览器扩展、浏览器开发者工具中的“网络”选项卡以及 Postman 等应用程序都是已安装的软件。它们不会仅仅因为您访问了另一个网站*就将数据从一个网站传递到属于另一个网站的 JavaScript 。安装软件通常需要更有意识的选择。

没有第三方(马洛里)被视为风险。

*浏览器扩展确实需要谨慎编写以避免跨域问题。请参阅 Chrome 文档作为示例。

网页内

大多数情况下,仅在网页上显示某些内容并不会导致大量信息泄露。

如果您使用<img>元素加载图像,则该图像会显示在页面上,但很少的信息会暴露给 Mallory。JavaScript 无法读取图像(除非您使用属性crossOrigin明确启用 CORS 请求权限),然后将其复制到她的服务器。

尽管如此,一些信息确实泄露了,引用谷歌的 Domenic Denicola 的话:

网络的基本安全模型是同源策略。在该安全模型实施之前,我们有几个对该规则的遗留例外,其中脚本标签是最恶劣和最危险的例外之一。(请参阅各种“JSONP”攻击。)

很多年前,也许是在引入 XHR 或 Web 字体时(我记不清具体时间了),我们划了一条底线,规定任何新的 Web 平台功能都不会破坏同源策略。现有功能需要保留,并受到精心设计且经常被利用的例外约束,以免破坏 Web,但我们肯定不能再给我们的安全策略增加任何漏洞。

这就是为什么需要 CORS 权限才能跨来源加载字体的原因。


为什么用JS不用读取数据就能在页面上显示出来

在许多情况下,Mallory 的网站可能会导致浏览器从第三方获取数据并显示数据(例如,通过添加元素<img>来显示图像)。不过,Mallory 的 JavaScript 无法读取该资源中的数据,只有 Alice 的浏览器和 Bob 的服务器可以这样做,因此它仍然是安全的。


CORS

错误消息中提到的 HTTP 响应标头是 CORS 标准的一部分,标准Access-Control-Allow-Origin允许Bob 明确授予 Mallory 的网站通过 Alice 的浏览器访问数据的权限。

基本实现仅包括:

Access-Control-Allow-Origin: *

…在响应标头中允许任何网站读取数据。

Access-Control-Allow-Origin: http://example.com

... 只允许特定站点访问它,并且 Bob 可以根据请求标头动态生成该Origin 请求标头,以允许多个(但不是所有)站点访问它。

Bob 如何设置该响应标头的具体细节取决于 Bob 的 HTTP 服务器和/或服务器端编程语言。Node.js/Express.js 的用户应使用文档齐全的 CORS 中间件。其他平台的用户应查看此指南集合,了解可能有帮助的各种常见配置。

CORS 规则应用模型

注意:有些请求很复杂,会发送预检OPTIONS 请求,服务器必须先响应该请求,然后浏览器才会发送 JS 想要发出的 GET/POST/PUT/Whatever 请求。仅添加Access-Control-Allow-Origin到特定 URL 的 CORS 实现通常会因此而受阻。


显然,Bob 只有在以下情况下才会通过 CORS 授予权限:

  • 数据不是私人的,或者

  • 马洛里受到信任


我如何添加这些标题?

这取决于您的服务器端环境。

如果可以的话,请使用专门设计用于处理 CORS 的库,因为它们会为您提供简单的选项,而不必手动处理所有事情。

Enable-Cors.org列出了特定平台和框架的文档,您可能会觉得有用。

但我不是鲍勃!

没有标准机制让Mallory添加此标头,因为它必须来自 Bob 的网站,而她无法控制该网站。

如果 Bob 正在运行公共 API,那么可能存在一种启用 CORS 的机制(可能通过以某种方式格式化请求,或者在登录 Bob 网站的开发者门户网站后配置选项)。但这必须由 Bob 实施。Mallory 可以阅读 Bob 网站上的文档,看看是否有可用的方法,或者她可以与 Bob 交谈并要求他实施 CORS。


提及“预检响应”的错误消息

一些跨域请求是经过预检的。

粗略地说,当您尝试发出跨源请求时,就会发生这种情况:

  • 包括 Cookie 等凭证

  • 无法使用常规 HTML 表单生成(例如,设置无法在表单enctype或其他请求标头中使用的 Content-Type)。

如果你正确地做了一些需要预检的事情

在这些情况下,这个答案的其余部分仍然适用,但您还需要确保服务器可以监听预检请求(将是OPTIONS(而不是GETPOST或您尝试发送的任何内容)并使用正确的Access-Control-Allow-Origin标头对其进行响应,同时也Access-Control-Allow-Methods允许Access-Control-Allow-Headers您的特定 HTTP 方法或标头。

如果你误触发了预检

有时人们在尝试构建 Ajax 请求时会犯错误,有时这些错误会触发预检的需要。如果 API 设计为允许跨源请求,但不需要任何需要预检的内容,那么这可能会中断访问。

引发此问题的常见错误包括:

  • 尝试将Access-Control-Allow-Origin和其他 CORS 响应标头放在请求中。这些不属于请求,不会做任何有用的事情(您可以授予自己权限的权限系统有什么意义?),并且必须仅出现在响应中。

  • 尝试Content-Type: application/json在没有请求主体的 GET 请求上放置一个标头,而该请求主体的内容需要描述(通常是当作者混淆Content-Type和时Accept)。

在任何一种情况下,删除额外的请求标头通常就足以避免预检的需要(这将解决与支持简单请求但不支持预检请求的 API 通信时的问题)。


不透明响应(no-cors模式)

有时您需要发出 HTTP 请求,但不需要读取响应。例如,如果您正在将日志消息发布到服务器进行记录。

如果您正在使用APIfetch(而不是),那么您可以XMLHttpRequest将其配置为不尝试使用 CORS。

请注意,这不会让您执行任何需要 CORS 执行的操作您将无法读取响应。您将无法发出需要预检的请求。

它会让你发出一个简单的请求,但看不到响应,也不会在开发者控制台中填充错误消息。

fetch当您使用CORS 发出请求并且没有获得查看响应的权限时,Chrome 给出的错误消息解释了如何操作:

CORS 策略已阻止从https://example.com/源“ ”获取“ ”的权限:请求的资源上不存在“ ”标头。如果不透明响应满足您的需求,请将请求的模式设置为“no-cors”以在禁用 CORS 的情况下获取资源。https://example.net`Access-Control-Allow-Origin`

因此:

fetch("http://example.com", { mode: "no-cors" });

CORS 的替代方案

JSON协议

Bob 还可以使用JSONP之类的黑客技术来提供数据,这是在 CORS 出现之前人们进行跨源 Ajax 的方式。

它的工作原理是将数据以 JavaScript 程序的形式呈现,然后将其注入 Mallory 的页面。

它要求 Mallory 相信 Bob 不会提供恶意代码。

请注意共同的主题:提供数据的网站必须告诉浏览器,第三方网站可以访问其发送到浏览器的数据。

由于 JSONP 的工作原理是附加一个<script>元素,以调用页面中已有函数的 JavaScript 程序的形式加载数据,因此尝试在返回 JSON 的 URL 上使用 JSONP 技术将会失败(通常会出现 CORB 错误),因为 JSON 不是 JavaScript。

将两个资源移至单个源

如果 JS 运行的 HTML 文档和请求的 URL 位于同一来源(共享相同的方案、主机名和端口),则同源策略默认授予权限。不需要 CORS。

代理

马洛里可以使用服务器端代码来获取数据(然后她可以像往常一样通过 HTTP 将数据从她的服务器传递到爱丽丝的浏览器)。

它将:

  • 添加 CORS 标头

  • 将响应转换为 JSONP

  • 与 HTML 文档同源

该服务器端代码可以由第三方(例如 CORS Anywhere)编写和托管。请注意,这样做会对隐私产生影响:第三方可以监控谁在其服务器上代理了什么。

鲍勃不需要授予任何权限即可实现这一点。

这里不存在任何安全隐患,因为这只是 Mallory 和 Bob 之间的事。Bob 不可能认为 Mallory 就是 Alice,也不可能向 Mallory 提供 Alice 和 Bob 之间应该保密的数据。

因此,Mallory 只能使用这种技术来读取公共数据。

但请注意,从其他人的网站上获取内容并在您自己的网站上展示可能会侵犯版权,并可能导致您面临法律诉讼。

编写除 Web 应用程序之外的其他内容

正如“为什么同源策略仅适用于网页中的 JavaScript”部分所述,您可以通过不在网页中编写 JavaScript 来避免 SOP。

这并不意味着您不能继续使用 JavaScript 和 HTML,但您可以使用其他机制(例如 Node-WebKit 或 PhoneGap)来分发它。

浏览器扩展

在应用同源策略之前,浏览器扩展可能会在响应中注入 CORS 标头。

这些对于开发很有用,但对于生产站点来说并不实用(要求站点的每个用户都安装禁用其浏览器安全功能的浏览器扩展是不合理的)。

它们也往往只适用于简单请求(处理预检 OPTIONS 请求时失败)。

拥有具有本地开发服务器的适当的开发环境
通常是更好的方法。


其他安全风险

请注意,SOP / CORS 不会缓解需要独立处理的XSS、CSRF或SQL 注入攻击。


概括

  • 您无法在客户端代码中执行任何操作来启用对其他人服务器CORS 访问。

  • 如果您控制服务器,则会发出请求:向其添加 CORS 权限。

  • 如果您与控制它的人关系友好:让他们向它添加 CORS 权限。

  • 如果它是一项公共服务,那么(请记住,大多数第三方 API 都设计为仅与服务器端代码交互,并且不支持 CORS,但对于那些支持的 API):

    • 阅读他们的 API 文档,了解他们关于使用客户端 JavaScript 访问它的说法:

      • 他们可能会告诉你使用特定的 URL

      • 他们可能支持 JSONP 而不是 CORS

      • 他们可能根本不支持从客户端代码进行跨域访问(这可能是出于安全原因而做出的故意决定,特别是如果您必须在每个请求中传递个性化的 API 密钥)。

    • 确保您没有触发不需要的预检请求。API 可能会授予简单请求的权限,但不会授予预检请求的权限。

  • 如果以上都不适用:让浏览器与您的服务器通信,然后让您的服务器从其他服务器获取数据并将其传递。(还有第三方托管服务将 CORS 标头附加到您可以使用的可公开访问的资源)。

解决方案 2:

目标服务器必须允许跨源请求。为了允许它通过 express,只需处理 http 选项请求:

app.options('/url...', function(req, res, next){
   res.header('Access-Control-Allow-Origin', "*");
   res.header('Access-Control-Allow-Methods', 'POST');
   res.header("Access-Control-Allow-Headers", "accept, content-type");
   res.header("Access-Control-Max-Age", "1728000");
   return res.sendStatus(200);
});

解决方案 3:

因为这没有在接受的答案中提及。

  • 对于这个确切的问题来说,情况并非如此,但可能会帮助其他搜索该问题的人

  • 您可以在客户端代码中执行此操作,以防止在某些情况下出现 CORS 错误。

您可以使用简单请求。

为了执行“简单请求”,请求需要满足几个条件。例如,仅允许POSTGETHEAD方法,以及仅允许某些给定的标头(您可以在此处找到所有条件)。

如果您的客户端代码没有在请求中使用固定值明确设置受影响的标头(例如“Accept”),则可能会发生某些客户端会自动使用某些“非标准”值设置这些标头,导致服务器不接受它作为简单请求 - 这将为您提供 CORS 错误。

解决方案 4:

这是由于 CORS 错误而发生的。CORS 代表跨源资源共享。简而言之,当我们尝试从另一个域访问一个域/资源时,就会发生此错误。

在这里阅读更多相关信息:jquery 的 CORS 错误

要解决此问题,如果您有权访问其他域,则必须在服务器中允许 Access-Control-Allow-Origin。这可以添加到标头中。您可以为所有请求/域或特定域启用此功能。

如何使跨域资源共享 (CORS) 发布请求正常工作

这些链接可能有帮助

解决方案 5:

由于其他原因,此 CORS 问题未得到进一步阐述。

我目前遇到这个问题,原因不同。我的前端也返回了“Access-Control-Allow-Origin”标头错误。

只是我指向了错误的 URL,所以这个标题没有正确反映(我一直假设它确实如此)。localhost(前端)->调用非安全 http(应该是 https),确保前端的 API 端点指向正确的协议。

解决方案 6:

我在 Chrome 控制台中遇到了同样的错误。

http://我的问题是,我尝试使用而不是访问网站https://。因此,没有什么需要修复的,只需使用 访问同一网站即可https

解决方案 7:

这个错误耗费了我两天时间。我检查了我的服务器日志,Chrome/Edge 浏览器和服务器之间的预检选项请求/响应没有问题。主要原因是 XHTMLRequest 的 GET/POST/PUT/DELETE服务器响应也必须具有以下标头:

access-control-allow-origin: origin  

“origin” 在请求头中(浏览器会将其添加到请求中)。例如:

Origin: http://localhost:4221

您可以添加如下所示的响应标头以让所有内容接受:

access-control-allow-origin: *  

或者特定请求的响应标头,例如:

access-control-allow-origin: http://localhost:4221 

浏览器中的消息不清楚:“...请求的资源”

请注意:
CORS 适用于 localhost。不同的端口意味着不同的域。如果收到错误消息,请检查服务器端的 CORS 配置。

解决方案 8:

在大多数住房服务中,只需在目标服务器文件夹中的 .htaccess 中添加以下内容:

标头设置 Access-Control-Allow-Origin 'https://your.site.folder'

解决方案 9:

我遇到了同样的问题。就我而言,我通过timestamp向 URL 添加附加参数来修复此问题。即使我访问的服务器不需要这样做。

例如 yoururl.com/yourdocument?timestamp=1234567

注意:我使用了 epos 时间戳

解决方案 10:

带有附加标头的“Get”请求转换为“Options”请求。因此会出现 Cors 策略问题。您必须在服务器中实现“Options”请求。Cors Policy 是关于服务器端的,您需要在服务器端允许 Cors Policy。对于 Nodejs 服务器:详情

app.use(cors)

Java 与 Angular 集成:详细信息

@CrossOrigin(origins = "http://localhost:4200")

解决方案 11:

您应该启用 CORS 才能使其正常工作。

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   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源码管理

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

免费试用