djangodockerdjango-rest-frameworkcorsdjango-cors-headers

docker react+django, Access to XMLHttpRequest at 'http://localhost:8000' from origin 'http://localhost' has been blocked by CORS policy


I have a docker running with a service on the backend with Django and DRF, and another at the frontend with react I'm trying to make an API call from my react to my Django server

const getRealItems = () => {
    axios.get(`http://localhost:8000/item`).then(
      (response) => {
        console.log("realItems = ", response)
      }
    )
  }

this endpoint works normally on a browser or through insomnia and returns a 200 with the data, I have also tried to replace the endpoint on my method to the pokemon API and received a 200 with the data, so the method is fine

the issue is hitting the endpoint on my server

This is my settings.py

...

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    ...
    'rest_framework',
    'restaurant',
    'corsheaders',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

CORS_ALLOWED_ORIGINS = [
    "http://localhost",
    "http://localhost:80",
]

CORS_ORIGIN_ALLOW_ALL = True

...

and I added this on my viewset.py

class MenuItemViewSet(ModelViewSet):
    queryset = MenuItem.objects.all()
    serializer_class = MenuItemSerializer

    #GET
    def list(self, request, *args, **kwargs):
        return super().list(request, *args, **kwargs)

    def finalize_response(self, request, response, *args, **kwargs):
        response["Access-Control-Allow-Origin"] = "*"
        return super().finalize_response(request, response, *args, **kwargs)

This is my docker-compose in the case is necessary

version: "3.7"
services:

  database:
    build:
      context: .
      dockerfile: Dockerfile.postgres
    restart: always
    user: root
    volumes:
      - ./backup_data/db:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=postgres
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres

  backend:
    build: ./backend
    volumes:
      - ./backend:/app
    depends_on:
      - database
  
  frontend:
    build: ./frontend
    volumes:
      - ./frontend:/app
      - /app/node_modules
    depends_on:
      - backend
    ports:
      - 80:80

  do-migration:
    build: ./backend
    depends_on:
      - backend
    command:
      - /bin/bash
      - -c
      - |
        echo "Apply migration"
        python manage.py makemigrations
        python manage.py migrate
        exit 0
    volumes:
      - ./backend:/app
  
  nginx_backend_server:
    build: ./nginx_backend_server
    restart: always
    ports:
        - 8000:8000
    depends_on:
        - backend

but I'm stuck with this error:

Access to XMLHttpRequest at 'http://localhost:8000/item' from origin 'http://localhost' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Edit1:

add a few modifications to my settings.py, same error

CORS_ALLOWED_ORIGINS = [
    "http://localhost",
    "http://localhost:8000",
]

CORS_ORIGIN_ALLOW_ALL = True

CORS_ALLOW_METHODS = ("DELETE", "GET", "OPTIONS", "PATCH", "POST", "PUT")

CORS_ALLOW_HEADERS = (
    "accept",
    "accept-encoding",
    "authorization",
    "content-type",
    "dnt",
    "user-agent",
    "x-csrftoken",
    "x-requested-with",
    "x-user-agent",
)

Could it be some missing config on my frontend app??


Solution

  • After a whole weekend on this, I figured out the solution in case anybody stumbles on this in the future:

    on INSTALLED_APPS, the corsheaders has to be above your app

    CORS_ORIGIN_WHITELIST = [
        'http://localhost',
        'http://localhost:3000',  # for localhost (REACT Default)
    ]
    
    CORS_ALLOWED_ORIGINS = [
        'http://localhost',
        'http://localhost:3000',  # for localhost (REACT Default)
    ]
    
    CORS_ALLOW_HEADERS = ["origin"]
    
    CORS_ORIGIN_ALLOW_ALL = True
    CORS_ALLOW_ALL_ORIGINS = True
    

    A curl request should have the Referrer-policy set

    curl -I http://localhost:8000
    
    HTTP/1.1 200 OK
    Server: nginx/1.20.1
    Date: Mon, 03 Apr 2023 02:22:15 GMT
    Content-Type: application/json
    Content-Length: 69
    Connection: keep-alive
    Vary: Accept, Cookie, Origin
    Allow: GET, HEAD, OPTIONS
    X-Frame-Options: DENY
    X-Content-Type-Options: nosniff
    Referrer-Policy: same-origin
    

    and lastly, on my get: axios.get(http://localhost:8000/item)

    was being redirected to 'http://localhost:8000/item/', and so I had to append the trailing / to my requests