ChatGPT解决这个技术问题 Extra ChatGPT

XMLHttpRequest 无法加载 XXX No 'Access-Control-Allow-Origin' 标头

tl;博士;关于同源策略

我有一个启动 express.js 服务器实例的 Grunt 进程。直到现在它开始提供空白页面,并且在 Chrome(最新版本)的开发人员控制台中的错误日志中显示以下内容时,这一直工作得非常好:

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

是什么阻止我访问该页面?

我正在网站上工作,五分钟前还好。
它会发出 CORS 标头吗?也许如果您共享一些代码会更容易看到
似是而非。我应该向哪个部门查询?我只是做骨干。木偶的东西主要是……
是的。我想部门的组织并不总是统一的,所以这可能是一个模糊的问题,但我想知道我公司的一些后端/路由/系统管理员的东西,这似乎是一个熟悉的好借口我自己,所以如果将来有问题我可以提供帮助。
我会在您的操作中询问服务器端的某个人。如果您之前能够访问它,他们一定已经对您进行了更改。

j
jub0bs

tl;dr - 答案的末尾和标题有一个摘要,以便更容易找到相关部分。建议阅读所有内容,因为它为理解原因提供了有用的背景,这使得了解如何在不同情况下更容易应用。

关于同源策略

这是 Same Origin Policy。它是浏览器实现的安全功能。

您的特殊情况显示了它是如何为 XMLHttpRequest 实现的(如果您使用 fetch,您将获得相同的结果),但它也适用于其他事物(例如加载到 <canvas> 的图像或加载到 { 2}),只是实现略有不同。

(奇怪的是,它也适用于 CSS 字体,但那是因为找到的代工厂坚持 DRM,而不是同源政策通常涵盖的安全问题)。

可以使用 three characters 演示证明需要 SOP 的标准场景:

爱丽丝是一个拥有网络浏览器的人

Bob 运行一个网站(在您的示例中为 https://www.[website].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)……除非您将画布混入其中,在这种情况下 产生同源违规错误)。

为什么在您认为不应该适用同源政策时适用

对于任何给定的 URL,可能不需要 SOP。出现这种情况的几个常见场景是:

爱丽丝、鲍勃和马洛里是同一个人。

Bob 提供完全公开的信息

…但是浏览器无法知道上述任何一个是否正确,因此信任不是自动的,而是应用了 SOP。在浏览器将其提供给不同网站的数据之前,必须明确授予权限。

为什么同源策略仅适用于网页中的 JavaScript

浏览器扩展程序*、浏览器开发者工具中的“网络”标签和 Postman 等应用程序都是已安装的软件。他们不会将数据从一个网站传递到属于不同网站的 JavaScript只是因为您访问了那个不同的网站。安装软件通常需要更谨慎的选择。

没有第三方(马洛里)被认为是有风险的。

* 浏览器扩展确实需要仔细编写以避免跨域问题。 See the Chrome documentation for example

为什么用JS不用读取就可以在页面中显示数据

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

CORS

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

一个基本的实现将只包括:

Access-Control-Allow-Origin: *

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

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

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

Bob 如何设置响应头的细节取决于 Bob 的 HTTP 服务器和/或服务器端编程语言。 Node.js/Express.js 的用户应使用 well-documented CORS middleware。其他平台的用户应该看看这个可能有帮助的 collection of guides for various common configurations

https://i.stack.imgur.com/VXM0t.png

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

显然,通过 CORS 授予权限是 Bob 仅在以下情况下才会做的事情:

数据不是私人的或

马洛里是值得信赖的

如何添加这些标题?

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

如果可以,请使用旨在处理 CORS 的库,因为它们会为您提供简单的选项,而不必手动处理所有内容。

Enable-Cors.org 包含您可能会发现有用的特定平台和框架的文档列表。

但我不是鲍勃!

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

如果 Bob 正在运行一个公共 API,那么可能有一种机制可以打开 CORS(可能通过以某种方式格式化请求,或者在登录到 Bob 站点的 Developer Portal 站点后的配置选项)。不过,这必须是 Bob 实现的一种机制。 Mallory 可以阅读 Bob 网站上的文档以查看是否有可用的内容,或者她可以与 Bob 交谈并要求他实施 CORS。

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

一些跨源请求是 preflighted

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

包括 cookie 等凭据

无法使用常规 HTML 表单生成(例如,具有您无法在表单的 enctype 中使用的自定义标题或 Content-Type)。

如果您正确地做需要预检的事情

在这些情况下,此答案的其余部分仍然适用,但您还需要确保服务器可以侦听预检请求(将是 OPTIONS(而不是 GET,{3 } 或您尝试发送的任何内容)并使用正确的 Access-Control-Allow-Origin 标头以及 Access-Control-Allow-MethodsAccess-Control-Allow-Headers 来响应它以允许您的特定 HTTP 方法或标头。

如果您错误地触发了预检

有时人们在尝试构建 Ajax 请求时会出错,有时这些会触发预检的需要。如果 API 旨在允许跨域请求,但不需要任何需要预检的东西,那么这可能会中断访问。

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

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

试图将 Content-Type: application/json 标头放在没有请求正文来描述其内容的 GET 请求上(通常当作者混淆 Content-Type 和 Accept 时)。

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

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

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

如果您使用的是 the fetch API(而不是 XMLHttpRequest),那么您可以将其配置为不尝试使用 CORS。

请注意,这不会让您做任何需要 CORS 做的事情。您将无法阅读回复。您将无法提出需要预检的请求。

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

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

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

因此:

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

CORS 的替代品

JSONP

Bob 还可以使用像 JSONP 这样的 hack 来提供数据,这就是人们在 CORS 出现之前进行跨域 Ajax 的方式。

它通过以 JavaScript 程序的形式呈现数据来工作,该程序将数据注入 Mallory 的页面。

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

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

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

将两个资源移动到一个 Origin

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

代理

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

它将:

添加 CORS 标头

将响应转换为 JSONP

与 HTML 文档同源

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

Bob 不需要为此授予任何权限。

这里没有安全隐患,因为那只是在 Mallory 和 Bob 之间。 Bob 无法认为 Mallory 就是 Alice,也无法向 Mallory 提供 Alice 和 Bob 之间应该保密的数据。

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

但是请注意,从其他人的网站上获取内容并自行显示可能会侵犯版权,并让您面临法律诉讼。

编写网络应用程序以外的东西

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

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

浏览器扩展

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

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

它们也倾向于只处理简单的请求(在处理预检 OPTIONS 请求时失败)。

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

其他安全风险

请注意,SOP / CORS 不能缓解需要独立处理的 XSSCSRFSQL Injection 攻击。

概括

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

如果您控制正在向其发出请求的服务器:向其添加 CORS 权限。

如果您对控制它的人友好:让他们为其添加 CORS 权限。

如果它是一项公共服务:阅读他们的 API 文档以了解他们对使用客户端 JavaScript 访问它的看法:他们可能会告诉您使用特定的 URL 他们可能支持 JSONP 他们可能不支持从客户端代码进行跨域访问完全没有(这可能是出于安全原因的深思熟虑的决定,特别是如果您必须在每个请求中传递个性化的 API 密钥)。确保您没有触发不需要的预检请求。 API 可能会授予简单请求的权限,但不会授予预检请求的权限。

阅读他们的 API 文档以了解他们对使用客户端 JavaScript 访问它的看法: 他们可能会告诉您使用特定的 URL 他们可能支持 JSONP 他们可能根本不支持从客户端代码进行跨域访问(这可能是出于安全考虑的深思熟虑的决定,特别是如果您必须在每个请求中传递个性化的 API 密钥)。

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

他们可能支持 JSONP

它们可能根本不支持从客户端代码进行跨域访问(这可能是出于安全考虑而深思熟虑的决定,尤其是在您必须在每个请求中传递个性化 API 密钥的情况下)。

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

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


如果我在本地 LAN 上运行一个 Web 服务器并尝试从 IP/URL 进行 ajax 加载,那会起作用吗?我还没有尝试过。因为我的 web 服务器返回 json 数据将是一个 MCU
@Ciastopiekarz — 适用正常的相同来源/不同来源规则。正常的网络路由规则适用。
我读过的最完整的答案,而不仅仅是关于 cors 的链接。
@Quentin - 哇! +1!所以我要理解的是,如果 Alice 使用 CORS 扩展,服务器认为她的 http 调用不是来自 javascript 而是来自浏览器扩展,并将其视为普通的同源请求?
@snippetkid — 不。在通常情况下,服务器将在任何响应中发送 CORS 标头,而不关心请求来自何处。浏览器有责任根据响应上的 CORS 标头允许或拒绝对 JS 数据的访问。 (当涉及到预检请求时,服务器上的事情会变得/有点/更复杂)
D
Daphoque

目标服务器必须允许跨域请求。为了允许它通过 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);
});

z
zwif

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

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

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

您可以使用 Simple Requests
为了执行“简单请求”,请求需要满足几个条件。例如只允许 POSTGETHEAD 方法,以及只允许某些给定的 Headers(您可以找到所有条件 here)。

如果您的客户端代码未在请求中使用固定值显式设置受影响的标头(例如“接受”),则可能会发生某些客户端确实使用某些“非标准”值自动设置这些标头,从而导致服务器不接受它作为简单请求 - 这会给你一个 CORS 错误。


C
Community

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

在此处阅读更多信息:CORS error with jquery

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

How to get a cross-origin resource sharing (CORS) post request working

这些链接可能会有所帮助


m
morph85

这个 CORS 问题没有进一步阐述(出于其他原因)。

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

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


S
Subhashi

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

我的问题是,我试图使用 http:// 而不是 https:// 访问该站点。所以没有什么可修复的,只需要使用 https 访问同一站点。


k
kira

带有附加标头的“获取”请求转换为“选项”请求。因此出现了 Cors 政策问题。您必须对您的服务器实施“选项”请求。


H
HungNM2

这个错误花了我 2 天的时间。我检查了我的服务器日志,浏览器 Chrome/Edge 和服务器之间的 Preflight Option 请求/响应正常。主要原因是 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 配置。


M
Massimo Pavanel

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

标题集 Access-Control-Allow-Origin 'https://your.site.folder'


I
Inshal irshad

我遇到过同样的问题。在我的情况下,我通过将 timestamp 的附加参数添加到我的 URL 来修复它。即使这不是我正在访问的服务器所要求的。

示例 yoururl.com/yourdocument?timestamp=1234567

注意:我使用了 epos 时间戳


P
Perostek Balveda

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