CORS

Access to fetched has been blocked by CORS policy

控制台中看到那个大红色错误时,每个开发人员都会感到沮丧!😬虽然有一些方法可以快速摆脱这个错误,但今天我们不要想当然!相反,让我们看看 CORS 实际上在做什么,以及为什么它实际上是我们的朋友

在前端,我们经常想显示位于其他地方的数据!在我们可以显示这些数据之前,浏览器首先必须向服务器发出请求以获取该数据!客户端发送一个 HTTP 请求,其中包含服务器需要的所有信息,以便将该数据发送回客户端

假设我们试图 www.mywebsite.com 从位于api.website.com

image.png

我们向服务器发送了一个 HTTP 请求,然后服务器响应了我们请求的 JSON 数据

让我们尝试完全相同的请求,但来自另一个域。www.mywebsite.com我们现在不是从 发出请求,而是从位于 的网站发出请求www.anotherdomain.com

image.png

我们发送了完全相同的请求,但这次浏览器向我们显示了一个奇怪的错误, 我们刚刚看到了 CORS 的作用, 什么会出现这个错误,以及它究竟意味着什么

同源政策

网络强制执行称为同源策略的东西。默认情况下,我们只能访问与请求源位于同一源的资源!https://mywebsite.com/image1.png例如,加载位于 的图像是完全可以的

当资源位于不同的(子)域、协议或端口时,它就是跨源的

image.png

为什么会存在同源策略?

假设同源策略不存在,并且您不小心点击了的朋友在 微博 上发送给您的众多病毒链接之一。此链接会将您重定向到一个"邪恶网站",该网站嵌入了一个 iframe,它会加载您银行的网站,并通过一些设置的 cookie 成功登录

这个“邪恶网站”的开发者使该网站可以访问这个 iframe 并与您银行网站的 DOM 内容进行交互,以便代表您向他们的账户汇款!

image.png

这是一个巨大的安全风险!我们不希望任何人都能访问所有内容

幸运的是,同源策略在这里帮助了我们!此策略确保我们只能访问来自同一来源的资源

image.png

在这种情况下,源www.evilwebsite.com尝试从www.bank.com 同源策略阻止了这种情况的发生,并确保邪恶网站的开发者不能只是访问我们的银行数据

客户端 CORS

虽然同源策略实际上只适用于脚本,但浏览器为 JavaScript 请求“扩展”了这个策略:默认情况下,我们只能访问来自同源的资源

image.png

我们经常要访问跨域资源,也许我们的前端需要与我们的后端 API 交互才能加载数据?为了安全地允许跨域请求,浏览器使用了一种叫做CORS的机制

CORS 代表跨域资源共享。尽管浏览器不允许我们访问位于不同来源的资源,但我们可以使用 CORS 稍微更改这些安全限制,同时仍然确保我们安全地访问这些资源

用户代理(例如浏览器)可以使用 CORS 机制,根据 HTTP 响应中某些特定于 CORS 的标头的值,允许跨域请求,否则这些请求将被阻止

当一个跨域请求,客户端会自动添加一个额外的头给我们的HTTP请求:OriginOriginheader的值就是请求的来源

image.png

为了让浏览器允许访问跨域资源,它需要来自服务器响应的某些标头,这些标头指定此服务器是否允许跨域请求

服务端CORS

作为服务器开发人员,我们可以通过在 HTTP 响应中添加额外的标Access-Control-*头来确保允许跨域请求,这些标头都以 headers 开头 基于这些 CORS 响应标头的值,浏览器现在可以允许某些跨域响应这通常会被同源策略阻止

尽管我们可以使用多个 CORS 标头,但浏览器需要一个标头以允许跨源资源访问: Access-Control-Allow-Origin

此标头的值指定允许哪些源访问它们从服务器请求的资源

如果我们正在开发一个https://mywebsite.com应该可以访问的服务器,我们可以将该域的值添加到Access-Control-Allow-Origin标头中

image.png

此标头现在已添加到服务器发送回客户端的响应中。通过添加此头相同的政策原点将不再限制我们无法收到资源都位于该https://api.mywebsite.com原点,如果我们从发出请求https://mywebsite.com

image.png

浏览器中的 CORS 机制会检查Access-Control-Allow-Originheader 的值是否等于Origin请求发送的值

在这种情况下,我们请求的来源是https://www.mywebsite.com,它列在Access-Control-Allow-Origin响应头中

image.png

我们能够成功接收到跨域资源!那么当我们试图从一个未在Access-Control-Allow-Origin标题中列出的来源访问这些资源时会发生什么?

image.png

CORS 引发了臭名昭著的错误,有时会令人沮丧!但现在我们实际上看到它完全有道理

The 'Access-Control-Allow-Origin' header has a value
 'https://www.mywebsite.com' that is not equal 
to the supplied origin. 

在这种情况下,提供的来源是https://www.anotherwebsite.com。但是,服务器在Access-Control-Allow-Origin标题的允许来源列表中没有提供这个来源!CORS成功拦截了请求,我们的代码中无法访问获取到的数据

CORS 还允许我们添加通配符*作为允许来源的值。这意味着来自所有来源的请求都应该可以访问所请求的资源

Access-Control-Allow-Origin是我们可以提供的众多 CORS 标头之一。服务器开发人员可以扩展服务器的 CORS 策略以(禁止)允许某些请求

另一个常见的标题是Access-Control-Allow-Methods标题!CORS 仅允许使用列出的方法发送的跨域请求

image.png

在这种情况下,只允许带有GET, POST, 或PUT方法的请求!其他方法如PATCH或DELETE将被阻止

说到PUT,PATCH和DELETE请求,CORS实际处理这些请求不同!🙃 这些“非简单”请求发起了一个叫做预检请求的事情

预检请求

CORS 有两种类型的请求:简单请求和预检请求。请求是简单的还是预检取决于请求中的一些值

当请求是一个GET or POST方法并且没有任何自定义标头时,请求很简单!任何其它请求,诸如与请求PUTPATCHDELETE方法,将被预检

在发送实际请求之前,客户端会生成一个预检请求!预检请求在其Access-Control-Request-*标头中包含有关我们即将执行的实际请求的信息

这为服务器提供了有关浏览器尝试发出的实际请求的信息:请求的方法是什么,附加的标头是什么,等等

image.png

服务器收到这个预检请求,并发送一个带有服务器 CORS 标头的空 HTTP 响应!浏览器收到预检响应,除了 CORS 标头之外不包含任何数据,并检查是否应该允许 HTTP 请求

image.png

如果是这种情况,浏览器会将实际请求发送到服务器,然后服务器以我们要求的数据进行响应

image.png

但是,如果不是这种情况,CORS 将阻止预检请求,而实际请求永远不会发送 预检请求是阻止我们访问或修改未启用任何 CORS 策略的服务器上的资源的好方法(然而)!服务器现在受到保护,免受可能不需要的跨域请求

为了减少到我们服务器的往返次数,我们可以通过向Access-Control-Max-AgeCORS 请求添加标头来缓存预检响应!我们可以通过这种方式缓存预检响应,浏览器可以使用它而不是发送新的预检请求

证书

默认情况下,Cookie、授权标头和 TLS 证书仅在同源请求上设置!但是,我们可能希望在跨域请求中使用这些凭据。也许我们想在请求中包含 cookie,服务器可以使用这些 cookie 来识别用户

尽管默认情况下 CORS 不包含凭据,但我们可以通过添加Access-Control-Allow-Credentials CORS 标头来更改它

如果我们想在我们的跨域请求中包含 cookie 和其他授权标头,我们需要在请求中将该withCredentials字段设置为true并将Access-Control-Allow-Credentials标头添加到响应中

image.png

可以了,好了!我们现在可以在跨域请求中包含凭据

虽然我认为我们都同意 CORS 错误有时会令人沮丧,但令人惊讶的是它使我们能够在浏览器中安全地发出跨域请求

点赞(1)

评论列表 共有 0 评论

暂无评论

微信服务号

微信客服

淘宝店铺

support@elephdev.com

发表
评论
Go
顶部