简体   繁体   中英

NGINX CORS Policy Fails when Access-Control-Allow-Origin Header is not present, but then sets it multiple times when header is present

Exactly what the title says, but for context:

I do have access to the upstream resource, and I am allowing all origins there.

When my NGINX conf does not include the directive add_header 'Access-Control-Allow-Origin' '*'; my browser tells me:

Access to XMLHttpRequest at 'http://localhost/{{ upstream_path_redacted }}' 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.

When I do include the above directive, my browser tells me

Access to XMLHttpRequest at 'http://localhost/{{ upstream_path_redacted }}' 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.

The second issue makes sense. As I stated, I am allowing all origins on the upstream server. I therefore don't understand why removing the directive causes the first issue.

My nginx.conf :

events {}
http {


    upstream my-upstream-service {
        server my-upstream-service:5000;
    }

    server {
        listen 80 default_server;

        location / {
            # this works fine. just included as base case.
            return 200 'ok';
            add_header Content-Type text/plain;
            add_header 'Access-Control-Allow-Origin' '*';
        }

        location /upstream {
            # removing the next uncommented line results in 'missing header' issue.
            # keeping it results in 'multiple header' issue.
            add_header 'Access-Control-Allow-Origin' '*';
            proxy_pass http://my-upstream-service;
        }
    }
}

What's confusing me even more: upon viewing the logs of both the my-upstream-server , and the nginx logs, the request is successfully being made to the upstream server???

All of my digging has brought me to solutions solving either one of the aforementioned issues, but not what to do when both are occuring. I'm stumped.

Further context if necessary: I am using docker-compose to deploy these services (inc. the front-end, which is a Vue SPA).

The my-upstream-service is a Flask webserver, using Flask-Cors.

Here's the docker-compose.yml

---
version: '3.8'

networks:
  gateway-service:
    driver: bridge
  
services:
  my-upstream-service:
    build:
      context: path/to/context/
      dockerfile: path/to/dockerfile
    ports:
      - "5000:5000"
    expose:
      - "5000"
    networks:
      - gateway-service

  frontend:
    build:
      context: /path/to/context
      dockerfile: /path/to/dockerfile
    ports:
      - "8080:8080"
    expose:
      - "8080"
    depends_on:
      - gateway
    networks:
      - gateway-service

  gateway:
    image: nginx:1.19.8-alpine
    volumes:
      # this is where my nginx.conf lives.
      - ./nginx/:/etc/nginx/
    ports:
      - "80:80"
    environment:
      - NGINX_PORT=80
    depends_on:
      - my-upstream-service
    networks:
      - gateway-service

I'm not sure why I got downvoted without any feedback regarding my question or why I was being downvoted.

Anyways, after a few hours of keyboard mashing I got something to work.

Essentially, also serving the Vue app behind the NGINX reverse proxy, while it created more issues, solved the issue described above in the long run.

I had to add additional configuration to both my Vue app and my NGINX conf to enable all of Vue's development capabilities to work completely. Here's a minimal version of the final NGINX conf:

events {}
http {
    upstream upstream-service {
        server upstream-service:5000;
    }

    upstream front-end {
        server front-end:8080;
    }


    server {
        listen 80 default_server;

        location / {
            proxy_pass http://front-end;
            proxy_set_header    Host                localhost;
            proxy_set_header    X-Real-IP           $remote_addr;
            proxy_set_header    X-Forwarded-Host    localhost;
            proxy_set_header    X-Forwarded-Server  localhost;
            proxy_set_header    X-Forwarded-Proto   $scheme;
            proxy_set_header    X-Forwarded-For     $remote_addr;
            proxy_redirect off;
            proxy_connect_timeout 90s;
            proxy_read_timeout 90s;
            proxy_send_timeout 90s;
        }

        location /sockjs-node {
            proxy_set_header X-Real-IP  $remote_addr;
            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_set_header Host $host;

            proxy_pass http://front-end; 

            proxy_redirect off;

            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }

        location /upstream {
            proxy_pass http://upstream-service;
        }
    }
}

I also had to add to my vue.config.js :

module.exports = {
    devServer: {
        disableHostCheck: true
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM