javascript express设置cors XMLHttpRequest无法加载XXX没有'Access-Control-Allow-Origin'标头




xmlhttprequest cors (5)

关于同源政策

这是 同源政策 。 它是由浏览器实现的安全功能。

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

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

演示SOP需求的标准方案可以用 三个字符 来演示:

  • Alice是一个拥有Web浏览器的人
  • Bob运行一个网站( https://www.[website].com/ 在您的示例中)
  • Mallory运行一个网站(在您的示例中为 http://localhost:4300

Alice登录Bob的网站,并在那里有一些机密数据。 也许它是一个公司内部网(只能访问局域网上的浏览器)或她的网上银行(只能通过输入用户名和密码后获得的cookie访问)。

Alice访问Mallory的网站,该网站有一些JavaScript,导致Alice的浏览器向Bob的网站发出HTTP请求(来自她的IP地址及其cookie等)。 这可以像使用 XMLHttpRequest 和读取 responseText 一样简单。

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

当您认为不应该使用同源策略时

对于任何给定的URL,可能不需要SOP。 在这种情况下,有两种常见情况是:

  • Alice,Bob和Mallory是同一个人。
  • 鲍勃提供完全公开的信息

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

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

浏览器扩展,浏览器开发工具中的网络选项卡和Postman等应用程序都是安装软件。 他们没有将数据从一个网站传递到属于不同网站的JavaScript, 只是因为您访问了不同的网站 。 安装软件通常需要更有意识的选择。

没有第三方(Mallory)被视为风险。

为什么你可以在不用JS阅读的情况下在页面中显示数据

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

CORS

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

基本实现只包括:

Access-Control-Allow-Origin: *

......允许任何网站阅读数据。

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

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

设置响应头的具体细节取决于Bob的HTTP服务器和/或服务器端编程语言。 有 一系列指南可供各种常见配置 使用。

注意:有些请求很复杂,并发送一个 preflight OPTIONS请求,服务器必须在浏览器发送GET / POST / PUT /无论JS想要的任何请求之前做出响应。 仅将 Access-Control-Allow-Origin 到特定URL的CORS实现通常会因此而被绊倒。

显然,通过CORS授予权限是Bob只有在以下任何一种情况下才会执行的操作:

  • 数据不是私人
  • 马洛里很受信任

如果您在这种情况下也是Bob,那么您添加CORS权限标头的具体细节将取决于您选择的HTTP服务器软件的某些组合以及您用于服务器端编程的语言(如果有)。

Mallory 无法添加此标题,因为她必须获得Bob的网站的许可,并且为了能够授予自己许可,这将是愚蠢的(使SOP变得毫无用处)。

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

一些交叉原始请求是 preflight

这种情况发生在(大致说来)您尝试制作跨源请求时:

  • 包括cookie等凭据
  • 无法使用常规HTML表单生成(例如,具有您无法在表单的 enctype 使用的自定义标头或Content-Type)。

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

在这些情况下 ,此答案的其余部分仍然适用, 但您还需要确保服务器可以监听预检请求(这将是 OPTIONS (而不是 GETPOST 或您尝试发送的任何内容)并对其进行响应使用正确的 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-TypeAccept )。

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

不透明的回应

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

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

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

它将允许您发出一个简单的请求,而不是查看响应,并且不会向Developer Console添加错误消息。

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

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

从而:

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

CORS的替代品

JSONP

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

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

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

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

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

将两个资源移动到单个Origin

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

代理人

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

它将:

  • 添加CORS标头
  • 将响应转换为JSONP
  • 存在于与HTML文档相同的原点

服务器端代码可以由第三方(例如CORS Anywhere)编写和托管。 请注意隐私含义:第三方可以监控谁代理服务器上的内容。

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文档,了解他们对使用客户端JavaScript访问它的看法。 他们可能会告诉您使用特定的URL或使用JSONP(或者他们可能根本不支持它)。
  • 如果以上都不适用:让浏览器改为与 您的 服务器通信,然后让您的服务器从其他服务器获取数据并将其传递。 (还有第三方托管服务将CORS标头附加到您可以使用的公共可访问资源)。

TL;博士; 关于同源政策

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

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

什么阻止我访问该页面?


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

我目前有这个问题有不同的原因。 我的前端也返回'Access-Control-Allow-Origin'标题错误。

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


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

  • 对于这个确切的问题,情况并非如此,但可能有助于其他人搜索该问题
  • 这是您可以在客户端代码中执行的操作,以防止在 某些情况下 出现CORS错误。

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

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


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

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







server