✋🏼🔥 CS Visualized: CORS


✋🏼🔥 CS Visualized: CORS - DEV

Cover image for ✋🏼🔥 CS Visualized: CORS

It’s every developer’s frustration once in a while to see that big red Access to fetched has been blocked by CORS policy error in your console! 😬 Although there are some ways to quickly get rid of this error, let’s not take anything for granted today! Instead, let’s see what CORS is actually doing, and why it’s actually our friend 👏🏼

每个开发人员都会不时感到沮丧,控制台中的因为 CORS 政策已阻止对获取访问的大红色错误! 😬 尽管有一些方法可以快速消除此错误,但今天我们不要将任何事情视为理所当然!相反,让我们看看 CORS 实际在做什么,以及为什么它实际上是我们的朋友 👏🏼

❗️ In this blog post I won’t explain HTTP basics. In case you’d like to know more about HTTP requests and responses, I wrote a small blog post about it a while ago though 🙂 In my examples I use HTTP/1.1 instead of HTTP/2, this doesn’t affect CORS.

❗️ 在此博客文章中,我不会解释 HTTP 基础知识.如果您想了解更多有关 HTTP 请求和响应的信息,尽管我在前不久写了一篇有关它的小博客文章 在我的示例中,我使用 HTTP / 1.1 代替 HTTP / 2,但这不会影响 CORS.


On the frontend, we often want to display data that’s located elsewhere! Before we can display this data, the browser first has to make a request to a server in order to fetch that data! The client sends an HTTP request with all the information that the server needs in order to send that data back to the client 🙂

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

Let’s say we’re trying to fetch some user information on our www.mywebsite.com website from a server that’s located at api.website.com!

假设我们正在尝试从 api.website.com 上的服务器上获取我们的 www.mywebsite.com 网站上的一些用户信息!

从 api.website.com 上的服务器上获取我们的 www.mywebsite.com 网站上的一些用户信息

Perfect! 😃 We just sent an HTTP request to the server, which then responded with the JSON data we asked for.

完美! 我们只是向服务器发送了 HTTP 请求,然后服务器用我们要求的 JSON 数据进行响应.

Let’s try the exact same request but from another domain. Instead of making the request from www.mywebsite.com, we’re now making the request from a website located at www.anotherdomain.com.

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

从位于 www.anotherdomain.com 的网站发出请求 浏览器向我们显示了一个奇怪的错误

Wait, what? We sent the exact same request, but this time the browser shows us a weird error?

等一下我们发送了完全相同的请求,但是这次浏览器向我们显示了一个奇怪的错误?

We just saw CORS in action! 💪🏼 Let’s see why this error occurred, and what it exactly means.

我们刚刚看到 CORS 发挥了作用! 💪🏼 让我们看看发生此错误的原因及其确切含义.


✋🏼 Same-Origin Policy

The web enforces something called the same-origin policy. By default, we can only access resources that are located at the same origin as the origin of our request! 💪🏼 It’s totally okay to load an image that’s located at https://mywebsite.com/image1.png, for example.

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

A resource is cross-origin when it’s located at a different (sub)domain, protocol, or port!

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

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

Cool, but why does the same-origin policy even exist?

但是为什么存在同源政策?

Let’s say that the same-origin policy didn’t exist, and you accidentally clicked one of the many virus links your aunt sent you on Facebook. This link redirects you to an “evil website” that has an iframe embedded which loads your bank’s website, and successfully logs you in by some set cookies! 😬

假设不存在同源政策,您无意中单击了姑姑在 Facebook 上发送给您的众多病毒链接之一.此链接会将您重定向到一个嵌入了 iframe 的”邪恶网站”,该 iframe 会加载您的银行网站,并通过设置的 Cookie 成功登录您! 😬

The developers of this “evil website” made it possible for the website to access this iframe and interact with the DOM contents of your bank’s website in order to send money to their account on your behalf!

这个”邪恶网站”的开发人员使该网站可以访问此 iframe,并与您银行网站的 DOM 内容进行交互,以便冒充您汇款到他们的帐户!

Alt Text

Yeah… this is a huge security risk! We don’t want anyone to just be able to access everything 😧

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

Luckily, the same-origin policy helps us out here! This policy makes sure that we can only access resources from the same origin.

幸运的是,同源政策可以帮助我们解决问题!这项政策确保我们只能访问同一来源的资源.

Alt Text

In this case, the origin www.evilwebsite.com tried to access cross-origin resources from www.bank.com! The same-origin policy blocked this from happening and made sure that the evil website’s devs couldn’t just access our bank data 🥳

在这种情况下,当 www.evilwebsite.com 试图从 www.bank.com 访问跨域资源!同源政策阻止了这种情况的发生,并确保邪恶网站的开发人员不能访问我们的银行数据

Okay, so… what does this have to do with CORS?

好的,那…这与 CORS 有什么关系?


🔥 Client-side CORS

Although the same-origin policy actually only applies to scripts, browsers “extended” this policy for JavaScript requests: by default, we can only access fetched resources from the same origin!

尽管同源策略实际上仅适用于脚本,但是浏览器将此策略”扩展”用于 JavaScript 请求:默认情况下,我们只能访问来自相同源的资源!

我们只能访问来自相同源的资源

Hmm, but… We often have to access cross-origin resources 🤔 Maybe our frontend needs to interact with our backend API in order to load the data? In order to allow cross-origin requests safely, the browser uses a mechanism called CORS! 🥳

嗯,但是…我们经常必须访问跨域资源 🤔 也许我们的前端需要与后端 API 进行交互才能加载数据?为了安全地允许跨域请求,浏览器使用了一种称为 CORS 的机制! 🥳

CORS stands for Cross-Origin Resource Sharing. Although the browser disallows us from accessing resources that aren’t located at the same origin, we can use CORS to change those security restrictions a bit while still making sure that we’re accessing those resources safely 🎉

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

User agents (a browser, for example) can use the CORS mechanism in order to allow cross-origin requests which otherwise would’ve been blocked, based on the values of certain CORS-specific headers in the HTTP response! ✅

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

When a cross-origin request is made, the client automatically adds an extra header to our HTTP request: Origin. The value of the Origin header is the origin where the request came from!

进行跨域请求时,客户端会自动向我们的 HTTP 请求中添加一个额外的标头:Origin. Origin 标头的值是请求的来源!

Alt Text

In order for the browser to allow accessing cross-origin resources, it expects certain headers from the server’s response, which specify whether this server allows cross-origin requests!

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


💻 Server-side CORS

As a server developer, we can make sure that cross-origin requests are allowed by adding extra headers to the HTTP response, which all start with Access-Control-* 🔥 Based on the values of these CORS response headers, the browser can now allow certain cross-origin responses which would’ve normally been blocked by the same-origin policy!

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

Although there are several CORS headers we can use, there is one header that the browser needs in order to allow cross-origin resource access: Access-Control-Allow-Origin! 🙂

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

The value of this header specifies which origins are allowed to access the resources that they’re requesting from the server.

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

If we’re developing a server that https://mywebsite.com should have access to, we can add the value of that domain to the Access-Control-Allow-Origin header!

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

Alt Text

Awesome! 🎉 This header is now added to the response that the server sends back to the client. By adding this header, the same-policy origin will no longer restrict us from receiving resources that were located at the https://api.mywebsite.com origin, if we sent the request from https://mywebsite.com!

太棒了! 现在 header 已添加到服务器发送回客户端的响应标头中.通过添加此标头,如果我们从 https://mywebsite.com 发送请求,则相同策略来源将不再限制我们接收位于 https://api.mywebsite.com 来源的资源!

Alt Text

The CORS mechanism within the browser checks whether the value of the Access-Control-Allow-Origin header equals the value of the Origin that was sent by the request 🤚🏼

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

In this case, the origin of our request is https://www.mywebsite.com, which is listed in the Access-Control-Allow-Origin response header!

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

Alt Text

Perfect! 🎉 We were able to receive the cross-origin resources successfully! So what happens when we’re trying to access these resources from an origin that’s not listed in the Access-Control-Allow-Origin header? 🤔

完美! 🎉 我们能够成功接收跨域资源!那么,当我们尝试从未在 Access-Control-Allow-Origin 标头中列出的来源访问这些资源时,会发生什么情况? 🤔

Alt Text

Ahh yeah, CORS throws the notorious error that can be so frustrating at times! But now we actually see that it makes total sense

嗯,是的,CORS 抛出了一个臭名昭著的错误,有时可能会令人沮丧!但是现在我们实际上看到这完全有意义

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

In this case, the supplied origin was https://www.anotherwebsite.com. However, the server didn’t have this supplied origin in the list of allowed origins in the Access-Control-Allow-Origin header! CORS successfully blocked the request, and we cannot access the fetched data in our code 😃

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

CORS also allows us to add the wildcard * as the value for the allowed origins. This means that requests from all origins should have access to the requested resources, so be careful!

CORS 还允许我们将通配符 * 添加为允许的来源的值.这意味着来自所有来源的请求都应该可以访问所请求的资源,因此请小心!


Access-Control-Allow-Origin is one of the many CORS headers we can provide. A server developer can extend the server’s CORS policies in order to (dis)allow certain requests! 💪🏼

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

Another common header is the Access-Control-Allow-Methods header! CORS will only allow cross-origin requests if they were sent with the listed methods.

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

Alt Text

In this case, only requests with a GET, POST, or PUT method will be allowed! Other methods such as PATCH or DELETE will be blocked ❌

在这种情况下,仅允许使用 GET,POSTPUT 方法的请求!诸如 PATCHDELETE 之类的其他方法将被阻止 ❌

If you’re curious about what the other possible CORS headers are and what they’re used for, check out this list.

如果您对其他可能的 CORS 标头是什么以及它们的用途感到好奇,请查看此列表.

Speaking of PUT, PATCH, and DELETE requests, CORS actually handles those requests differently! 🙃 These “non-simple“ requests initiate something called a preflight request!

说到 PUT,PATCHDELETE 请求,CORS 实际上以不同的方式处理这些请求! 🙃 这些”非简单”请求会启动所谓的预检请求!


🚀 Preflighted Requests

CORS has two types of requests: a simple request and a preflighted request. Whether a request is simple or preflighted depends on some values within the request (don’t worry, you don’t have to memorize this lol).

CORS 有两种类型的请求:简单请求和预检请求.请求是简单的还是预检的取决于请求中的某些值(不用担心,您不必记住这个).

A request is simple when the request is a GET or POST method and doesn’t have any custom headers! Any other request, such as requests with a PUT, PATCH, or DELETE method, will be preflighted.

如果请求是 GETPOST 方法且没有任何自定义标头,则请求是简单!其他任何请求(例如带有 PUT,PATCHDELETE 方法的请求)将被预检.

In case you’re just curious about which requirements a request has to meet in order to be a simple request, MDN has a useful list!

如果您只是想知道一个简单的请求必须满足哪些要求,MDN 会提供有用的清单!

Okay sure, but what does “preflighted request” even mean, and why does this happen?

好的,但是”预检请求”到底是什么意思,为什么会这样?


Before the actual request gets sent, the client generates a preflighted request! The preflighted request contains information about the actual request we’re about to in its Access-Control-Request-* headers 🔥

在发送实际请求之前,客户端会生成预检请求!预检请求在其 Access-Control-Request-* 标头中包含有关我们实际要处理的请求的信息 🔥

This gives the server information about the actual request that the browser is trying to make: what is the method of the request, what are the additional headers, and so on.

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

Alt Text

The server receives this preflighted request, and sends an empty HTTP response back with the server’s CORS headers! The browser receives the preflight response, which contains no data besides the CORS headers, and checks whether the HTTP request should be allowed! ✅

服务器接收到此预检请求,并使用服务器的 CORS 标头发送回空的 HTTP 响应!浏览器收到预检响应,该响应除了 CORS 标头外不包含任何数据,并检查是否应允许 HTTP 请求! ✅

Alt Text

If that’s the case, the browser sends the actual request to the server, which then responds with the data we asked for!

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

Alt Text

However, if it’s not the case, CORS will block the preflighted request, and the actual request never gets sent ✋🏼 The preflighted request is a great way to prevent us from accessing or modifying resources on servers that don’t have any CORS policies enabled (yet)! Servers are now protected from potentially unwanted cross-origin requests 😃

但是,如果不是这种情况,CORS 将阻止预检请求,并且实际请求将永远不会发送 ✋🏼 预检请求是防止我们访问或修改未启用任何 CORS 策略的服务器上资源的一种好方法!现在可以保护服务器免受潜在的跨域请求的攻击 😃

💡 In order to reduce the number of roundtrips to our server, we can cache the preflighted responses by adding an Access-Control-Max-Age header to our CORS requests! We can cache the preflighted response this way, which the browser can use instead of sending a new preflighted request!

💡 为了减少往返服务器的次数,我们可以通过在 CORS 请求中添加 Access-Control-Max-Age 标头来缓存预检响应!我们可以通过这种方式缓存预检响应,浏览器可以使用它来代替发送新的预检请求!


🍪 Credentials

Cookies, authorization headers, and TLS certificates are by default only set on same-origin requests! However, we may want to use these credentials in our cross-origin request. Maybe we want to include cookies on the request that the server can use in order to identify the user!

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

Although CORS doesn’t include credentials by default, we can change this by adding the Access-Control-Allow-Credentials CORS header! 🎉

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

If we want to include cookies and other authorization headers to our cross-origin request, we need to set the withCredentials field to true on the request and add the Access-Control-Allow-Credentials header to the response.

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

Alt Text

All set! We can now include credentials in our cross-origin request 🥳

搞定!现在,我们可以在跨域请求中包含凭据 🥳


Although I think we can all agree that CORS errors can be frustrating at times, it’s amazing that it enables us to safely make cross-origin requests in the browser (it should receive a bit more love lol) ✨

尽管我认为我们都同意 CORS 错误有时会令人沮丧,但令人惊奇的是,它使我们能够在浏览器中安全地进行跨域请求(它应该会收到更多的欢笑)✨

Obviously there is so much more to the same-origin policy and CORS than I was able to cover here in this blog post! Luckily, there are many great resources out there like this one or the W3 spec if you want to read more about it 💪🏼

显然,同源策略和 CORS 远远超出了我在本博文中能够介绍的范围!幸运的是,如果您想了解更多有关它的信息,那么这里有很多很棒的资源,例如《 W3 规范》.

And as always, feel free to reach out to me! 😊

和往常一样,随时与我联系! 😊

跨源资源共享(CORS)

浏览器的同源策略

CORS-safelisted response header


文章作者: Lydia Hallie
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Lydia Hallie !
  目录