• CORS (Cross-Origin Resource Sharing)

      NOTE : Les erreurs dues aux CORS sont généralement inféodées au navigateur !
      L’option mode de fetch() peut prendre une des quatre valeurs: ‘cors’, ‘no-cors’, ‘same-origin’, or ‘navigate’.
      Avec ‘cors’, le navigateur inclus un Origin dans le header de la requête et attend une réponse du serveur avec un header Access-Control-Allow-Origin disant qu’il accepte la requête. Si le serveur renvoit un header approprié, alors le navigateur autorise la réponse du serveur. Utile pour une API tiers.

       

      fetch('https://site.fr/api', {
         mode:  'cors'
         method: 'POST',
         headers: {
            'Content-Type': 'application/json'
         },
         body: JSON.stringify({
            key1: 'value1',
            key2: 'value2'
         })
      })
      .then(response => response.json())
      .then(data => console.log(data))
      .catch(error => console.error(error));

       

      fetch('https://example.com/api/data', {
         mode: 'no-cors'
      })
      .then(response => console.log(response))
      .catch(error => console.error(error));

      Dealing with CORS

      RAPPEL : une erreur CORS est une erreur côté CLIENT !!!

      If you have a project with a unified frontend and backend served on, say, localhost:8000the frontend can make requests to the backend without any issues or special treatment. If the frontend and backend are then split up, however, and the backend remains on localhost:8000 while the frontend is served from localhost:9000 now the browser considers those different domains and it will throw CORS errors.
      That last bit is important — it’s all up to the browser.

      Access-Control-Allow-Origin header is the very header that the browser is looking at to understand if the server wishes to allow requests from other domains! By default, servers won’t return any Access-Control-Allow-Origin headers which means that the browser will, by default, block cross-origin requests.

      A natural consequence of understanding that CORS errors are owned by the browser is the realization that any request that fails to a CORS error in the browser will succeed if requested outside of the browser.

      Resolving CORS Errors

      Make Your Domains (Origins) Match

      One of the most common patterns for resolving these issues is to simply avoid the issue entirely by ensuring that there is no sharing of cross-origin resources by configuring your servers such that your frontend and backend(s) are served from the same domain. The frontend may be served at the domain root and then backend resources under a subpath, for example /api/ .
      This approach is a bit trickier locally, especially if you’re not using additional webserver software like nginx as you might be in production to handle routing requests from a single local domain to different servers.
      For a contrived example, you could run your backend server at localhost:8000 , your frontend server at localhost:9000 and run your nginx server at localhost:5000. Then if you configure nginx to serve all requests to the /api/ path from locahost:8000 and all other requests from localhost:9000 then you would have a unified local domain at localhost:5000 that would no longer yield CORS errors! If all that sounds like a lot of work for a local environment, you’re right, which is why most local environments use the next approach.

      Return an Access-Control-Allow-Origin Header

      This is the easiest, most direct, solution, and in my opinion the most appropriate for local testing. If you have control over the server that is causing your browser to throw CORS errors, you can update that server to return the Access-Control-Allow-Origin header that the browser wants. The specific implementation will be different for each web server framework but the idea is simple and not any different from returning any other HTTP header. The header will look something like this:

      Access-Control-Allow-Origin: ‘*’
      That will allow cross-origin requests from any and all origins. Or, alternatively, if you wish to be a bit more specific you can return something like this, assuming localhost:9000 is the origin that your requests will come from:

      Access-Control-Allow-Origin: ‘http://localhost:9000′
      Read more about the details of this header here.

      Make Your Requests Outside of the Browser

      This approach is the most foolproof, and a great tool to have in your toolbox as a developer, but also the most involved.
      This comes up most often when you need to make requests to an API controlled by a third party. If you don’t own the endpoint in question you can’t change its domains or force it to return an Access-Control-Allow-Origin header — but you can avoid making the specific request that is throwing the CORS error within the user’s browser. CORS errors can essentially always be worked around by using a proxy to make the request for you.
      If you’re not familiar, a proxy server is just another server that is responsible only for forwarding a request to another server and returning the result. In this case, we would make the proxy server responsible for forwarding the request to the third-party endpoint for us, and in that way, the request would be made outside of the context of the browser, and thus CORS restrictions would not apply. Since the proxy server is under our control we’d have the ability to configure it to return the appropriate Access-Control-Allow-Origin header so we could then make our request to the proxy server from the browser without issue.
      There are many different ways to proxy a request, but ultimately it’s just as simple as mentioned before — a means to forward a request to another server and return the result. I’ve done this by creating small AWS Lambda functions, or even by creating one-off endpoints on my existing application that proxy the request — it doesn’t even have to be a whole separate server! Anything works, just so long as you make the cross-origin outside of the browser.

      Nginx easily solves cross-domain issues

      When you encounter a cross-domain problem, don’t immediately choose to copy it and try it. Please read this article in detail before processing. I believe it can help you.
      Preparation before analysis:

      First, make sure that the server does not handle cross-domain issues. Second, use postman to test whether the server interface is normal.

      When the website 8080 accesses the server interface, a cross-domain problem occurs. So how to solve it? Next, I will list various situations encountered across domains and solve them through nginx proxy (the same is true in the background, as long as you understand the principle).
      Cross-domain mainly involves 4 response headers:

      • Access-Control-Allow-Origin Used to set the source address that allows cross-domain requests (preflight requests and formal requests will be verified when cross-domain)
      • Access-Control-Allow-Headers Special header information fields allowed to be carried across domains (only verified in preflight requests)
      • Access-Control-Allow-Methods Cross-domain allowed request methods or HTTP verbs (only in preflight request verification)
      • Access-Control-Allow-Credentials Whether to allow the use of cookies across domains. If you want to use cookies across domains, you can add this request response header and set the value to true (setting it or not setting it will not affect the sending of the request, but will only affect whether cookies should be carried across domains. , but if set, both preflight requests and formal requests need to be set). However, it is not recommended to use it cross-domain (it has been used in the project, but it is unstable and cannot be carried by some browsers) unless necessary, because there are many alternatives.

      Many articles on the Internet tell you that adding these response headers directly to Nginx can solve cross-domain problems. Of course, most cases can be solved, but I believe there are still many cases where cross-domain problems will still be reported even if the configuration is correct. .
      What is a preflight request? : When a cross-domain condition occurs, the browser first asks the server whether the domain name of the current web page is in the server’s permission list, and which HTTP verbs and header information fields can be used. Only when a positive reply is received will the browser issue a formal XMLHttpRequestrequest, otherwise an error will be reported. As shown below

      Get started with the simulation:
      Nginx proxy port: 22222, configured as follows

      server {
      listen 22222;
      server_name localhost;
      location / {
      proxy_pass http://localhost:59200;
      }
      }
      Test whether the proxy is successful and access the interface again through Nginx proxy port 2222. You can see that the interface can be accessed normally after passing the proxy as shown below.

      Next, use website 8080 to access the interface address behind the Nginx proxy. The error message is as follows↓↓↓
      Case 1:

      Access to XMLHttpRequest at ‘http://localhost:22222/api/Login/TestGet’ from origin ‘http://localhost:8080′ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

      The error can be clearly located through the error message (pay attention to the red part). The priflight description is a pre-request. The CORS mechanism cross-domain will first perform a preflight (an OPTIONS request), and then the real request will be sent after the request is successful. This is designed to ensure servers are aware of the CORS standard to protect older servers that do not support CORS
      Through the error message, we can know that the request response header of the preflight request is missing Access-Control-Allow-Origin. If there is an error, we can just change it. Modify the Nginx configuration information as follows (the red part is the added part), fill in whatever is missing, it is very simple and clear

      server {
      listen 22222;
      server_name localhost;
      location / {
      add_header Access-Control-Allow-Origin ‘http://localhost:8080′;
      proxy_pass http://localhost:59200;
      }
      }
      Haha, when I was full of joy and thought it could be solved, I found that I still reported the same problem.

      However, there is nothing wrong with our configuration. The problem lies with Nginx.

      add_header The directive is used to add return header fields and is valid if and only if the status code is those listed in the figure. If you want every response message to carry header field information, you need to add always at the end (after my testing, only Access-Control-Allow-Originthis header information needs to be added with always, and other header information will be carried back without adding always), then let’s try adding it.

      server {
         listen       22222;
         server_name  localhost;
         location  / {
            add_header Access-Control-Allow-Origin 'http://localhost:8080' always;
            proxy_pass  http://localhost:59200;
         }
      }
      After  modifying the configuration, I found that it took effect. Of course, it  is not a cross-domain problem. The above problem has been solved  because the error content has changed.
      Case 2:

      Access to XMLHttpRequest at ‘http://localhost:22222/api/Login/TestGet’ from origin ‘http://localhost:8080′ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: It does not have HTTP ok status.

      It can be known from the error message that the pre-request (option request) that is the default behavior of the cross-domain browser does not receive the ok status code. At this time, the configuration file is modified. When the request is an option request, a status code is returned to the browser. (usually 204)

      server {
      listen 22222;
      server_name localhost;
      location / {
      add_header Access-Control-Allow-Origin ‘http://localhost:8080′ always;
      if ($request_method = ‘OPTIONS’) {
      return 204;
      }
      proxy_pass http://localhost:59200;
      }
      }
      After the configuration was completed, I found that the error message had changed.
      Case 3:

      Access to XMLHttpRequest at ‘http://localhost:22222/api/Login/TestGet’ from origin ‘http://localhost:8080′ has been blocked by CORS policy: Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response.

      This means that the authorization header information is missing in the pre-request response header Access-Control-Allow-Headers(each situation will be different. After cross-domain occurs, the custom header information added is not allowed and needs to be added to the request response header Access-Control-Allow-Headersso that the browser knows this The carrying of header information is recognized by the server as legal. What I carry here is authorization. Others may be tokens and the like. Add whatever is missing). Once you know the problem, then modify the configuration file, add the corresponding missing part, and try again. try

      server {
      listen 22222;
      server_name localhost;
      location / {
      add_header Access-Control-Allow-Origin ‘http://localhost:8080′ always;
      if ($request_method = ‘OPTIONS’) { add_header Access-Control-Allow-Headers ‘authorization’; #为什么写在if里面而不是接着Access-Control-Allow-Origin往下写?因为这里只有预检请求才会检查 return 204; } proxy_pass http://localhost:59200; }
      }
      At this time, it was found that the error reporting problem returned to situation 1.

      After testing, it has been verified that as long as if ($request_method = ‘OPTIONS’) it is written inside add_header , the external configuration will be invalid when making a preflight request. Why? ↓↓.
      The official documentation says this:

      There could be several add_header directives. These directives are inherited from the previous level if and only if there are no add_header directives defined on the current level.

      This means that add_header when there are no instructions at the current level, the ones from the previous level will be inherited add_header. On the contrary, if the current level exists add_header, it should not be able to inherit from the previous level add_header.

      The configuration modification is as follows:

      server {
      listen 22222;
      server_name localhost;
      location / {
      add_header Access-Control-Allow-Origin ‘http://localhost:8080′ always;
      if ($request_method = ‘OPTIONS’) {
      add_header Access-Control-Allow-Origin ‘http://localhost:8080′;
      add_header Access-Control-Allow-Headers ‘authorization’;
      return 204;
      }
      proxy_pass http://localhost:59200;
      }
      }
      At this time, after the modification, I found that the cross-domain problem has been solved.

      However, although the above solves the cross-domain problem, considering that the Nginx version may be updated in the future, I don’t know whether this rule will be modified. Considering that this writing method may carry two Access-Control-Allow-Origin , this situation is not allowed, as will be discussed below. arrive. So the configuration should be modified as follows:

      server {
      listen 22222;
      server_name localhost;
      location / {
      if ($request_method = ‘OPTIONS’) {
      add_header Access-Control-Allow-Origin ‘http://localhost:8080′;
      add_header Access-Control-Allow-Headers ‘authorization’;
      return 204;
      }
      if ($request_method != ‘OPTIONS’) {
      add_header Access-Control-Allow-Origin ‘http://localhost:8080′ always;
      }
      proxy_pass http://localhost:59200;
      }
      }
      It’s not over yet, keep chatting↓↓
      Case 4:
      Earlier APIs may only use POST and GET requests, and Access-Control-Allow-Methodsthis request response header only supports POST and GET across domains by default. When other request types occur, cross-domain exceptions will also occur.
      For example, I changed the requested API interface request method from the original GET to PUT and tried it again. On the console an error will be thrown:

      Access to XMLHttpRequest at ‘http://localhost:22222/api/Login/TestGet’ from origin ‘http://localhost:8080′ has been blocked by CORS policy: Method PUT is not allowed by Access-Control-Allow-Methods in preflight response.

      The error content is also very clear. In this pre-request, the PUT method is not allowed to be used in cross-domain. We need to change the Access-Control-Allow-Methodsconfiguration (is there anything missing? I only added PUT here. You can add it yourself. point) to let the browser know that the server is allowed

      server {
      listen 22222;
      server_name localhost;
      location / {
      if ($request_method = ‘OPTIONS’) {
      add_header Access-Control-Allow-Origin ‘http://localhost:8080′;
      add_header Access-Control-Allow-Headers ‘content-type,authorization’;
      add_header Access-Control-Allow-Methods ‘PUT’;#为这么只加在这个if中,不再下面的if也加上?因为这里只有预检请求会校验,当然你加上也没事。
      return 204;
      }
      if ($request_method != ‘OPTIONS’) {
      add_header Access-Control-Allow-Origin ‘http://localhost:8080′ always;
      }
      proxy_pass http://localhost:59200;
      }
      }
      Note here that after changing to PUT type, Access-Control-Allow-Headersthe request response header will automatically verify content-typethe request header, which is the same as case 3. Just make up for whatever is missing. If not added content-type, the following error will be reported.
      If you want to make it simple, Access-Control-Allow-Headersand Access-Control-Allow-Methodscan be set to * , which means they all match. However, Access-Control-Allow-Originit is not recommended to set * it up . For security reasons, it is necessary to restrict domain names.

      After adding them all, the problem is solved. The 405 reported here is that the interface on my server only opens GET and does not open PUT. At this moment, I use the PUT method to request this interface, so the interface will return this status code.

      Case 5:
      Finally, let me talk about another situation, that is, the backend handles cross-domain, and there is no need to handle it by yourself (here is a complaint, some backend engineers change the server code to solve cross-domain, but they don’t understand the principle, so they can find it on the Internet. The code snippet is pasted, resulting in incomplete processing of the response information. For example, the method is not added completely, the headers are not added to the point, the one you use may not contain the ones used in the actual project, and the options request is not returned with a status code. etc., causing Nginx to report the following exception if it reuses the common configuration)

      Access to XMLHttpRequest at ‘http://localhost:22222/api/Login/TestGet’ from origin ‘http://localhost:8080′ has been blocked by CORS policy: The ‘Access-Control-Allow-Origin’ header contains multiple values ‘*, http://localhost:8080′, but only one is allowed.

      This means that Access-Control-Allow-Originmultiple request response headers are returned at this moment, but only one is allowed. In this case, of course, you can modify the configuration and remove Access-Control-Allow-Originthis configuration. However, in this case, it is recommended that Nginx configuration and the server solve the cross-domain problem by themselves and only select other one.
      Note here that if you follow the way I wrote it above, you can’t delete if $request_method = ‘OPTIONS’ the ones inside Access-Control-Allow-Origin. Just delete !=’OPTIONS’the ones inside, because if it is a preflight request, it will be returned directly, and the request will not be forwarded to the 59200 service. If it is also deleted, it will The same error as case 1 will be reported. So why is it said that cross-domain should be solved at the server code level, or Nginx proxy should be used to solve it? Don’t mix it up, otherwise people who don’t understand the principle may not be able to solve the problem by looking for a piece of code posted online.
      Post a complete configuration again ( *fill in the number according to your own ‘preference’):

      server {
      listen 22222;
      server_name localhost;
      location / {
      if ($request_method = ‘OPTIONS’) {
      add_header Access-Control-Allow-Origin ‘http://localhost:8080′;
      add_header Access-Control-Allow-Headers ‘*’;
      add_header Access-Control-Allow-Methods ‘*’;
      add_header Access-Control-Allow-Credentials ‘true’;
      return 204;
      }
      if ($request_method != ‘OPTIONS’) {
      add_header Access-Control-Allow-Origin ‘http://localhost:8080′ always;
      add_header Access-Control-Allow-Credentials ‘true’;
      }
      proxy_pass http://localhost:59200;
      }
      }
      or:

      server {
      listen 22222;
      server_name localhost;
      location / {
      add_header Access-Control-Allow-Origin ‘http://localhost:8080′ always;
      add_header Access-Control-Allow-Headers ‘*’;
      add_header Access-Control-Allow-Methods ‘*’;
      add_header Access-Control-Allow-Credentials ‘true’;
      if ($request_method = ‘OPTIONS’) {
      return 204;
      }
      proxy_pass http://localhost:59200;
      }
      }
      Finally, this is an article about the process of solving cross-domain problems. If you read it carefully, I believe you can easily understand it and solve the problem yourself in actual use. I hope it can help everyone. The above content I came up with my own understanding of my own test code. If I understand anything wrong, please correct me.


      Nginx


      Cross Dom

       

      hubian

      Written by hubian

       





      Resolve CORS Errors Once and For All: Three Methods

       


      The Three Approaches for Resolving CORS Errors 

       

       

      NGINX — F5

 

Aucun commentaire

 

Laissez un commentaire