22

I cannot solve CORS problem in my Django API. When I make a call to this API, I get error:

Access to fetch at 'http://localhost:8000/' from origin 'http://localhost' 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. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

To enable CORS, I did pip install django-cors-headers and added the following code to settings.py:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'corsheaders',
]

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

CORS_ORIGIN_WHITELIST = [
    'localhost:80',
    'localhost:8000',
    '127.0.0.1:8000'
]

I should say that I run my project on Docker. This is docker-compose.yml:

version: '2'

services:
  django-docker:
    build:
      context: .
      dockerfile: Dockerfile.django
    container_name: my.django
    image: my-django
    ports:
      - 8000:8000

  webapp-docker:
    build:
      context: .
      dockerfile: Dockerfile.webapp
    container_name: my.webapp
    image: my-web
    ports:
      - 80:80
ScalaBoy
  • 3,254
  • 13
  • 46
  • 84

5 Answers5

28

You need to add corsheaders.middleware.CorsMiddleware middleware to the middleware classes in settings.py :

MIDDLEWARE_CLASSES = (
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.BrokenLinkEmailsMiddleware',
    'django.middleware.common.CommonMiddleware',
    #...
)

You have duplicate django.middleware.common.CommonMiddleware in your middleware classes.

You can then, either enable CORS for all domains by adding the following setting:

CORS_ORIGIN_ALLOW_ALL = True

Or Only enable CORS for specified domains:

CORS_ORIGIN_ALLOW_ALL = False

CORS_ORIGIN_WHITELIST = (
    'http://localhost:8000',
)
saurabheights
  • 3,967
  • 2
  • 31
  • 50
MSaadat
  • 644
  • 5
  • 10
  • 2
    Damn u, ':' is after http and not just before localhost. spent an hour figuring that out :D. +1 – saurabheights Sep 20 '19 at 19:54
  • I just spent a week debugging a nasty CORS issue. Notice that you cannot allow all when you have authorization. Also - the MIDDLEWARE_CLASSES are nowadays called MIDDLEWARE. – Paweł Załuski Mar 30 '21 at 13:25
  • If you've got rare case of API without any authentication you may also need to set `CORS_ALLOW_CREDENTIALS = False` (from https://stackoverflow.com/a/28834566/1927853) – Dmitriy Vinokurov Nov 27 '21 at 14:33
9

Try to add this in your settings:

from corsheaders.defaults import default_headers

CORS_ALLOW_HEADERS = default_headers + (
    'Access-Control-Allow-Origin',
)
Nevenoe
  • 1,032
  • 3
  • 14
  • 37
  • 1
    If you want to resolve quickly this issue add: CORS_ORIGIN_ALLOW_ALL = True. However, this is not a recommended production settings. Have you tried to set the name of your container in the CORS_ORIGIN_WHITELIST ? – Nevenoe Nov 02 '18 at 19:54
0

I got this error when I visited http://127.0.0.1:8000 in my browser but used fetch('http://localhost:8000'); in my JavaScript code. The solution is to use either 127.0.0.1 or localhost but not mix them.

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
  • That doesn't work because when you are using different ports it gets treated as a different domain. – Spartacus May 12 '21 at 21:36
  • @Spartacus In my case, the port was the same but I was using a different domain (even though they typically mean the same thing). If the ports differ then, you are correct, this won't solve the problem. Even with different ports, it is advisable to consitently use either `localhost` or `127.0.0.1` but not mix and match them. – Code-Apprentice May 14 '21 at 18:03
0

The only thing that helped me, was installing django-cors-headers:

pip install django-cors-headers

Then update the django settings.py file with the following:

INSTALLED_APPS = [
    ...
    "corsheaders",
    ...
]

MIDDLEWARE = [
    ...
    "corsheaders.middleware.CorsMiddleware",
    "django.middleware.common.CommonMiddleware",
    ...
]
Goomblepop
  • 41
  • 7
Vova
  • 3,117
  • 2
  • 15
  • 23
0

Here is another tip that I haven't seen mentioned anywhere.

When testing your Django app from a HTML file that you have stored locally and opened up from your file system, the submit form will have a Null origin.

Therefore to let CORS permit this you need to add Null to your CORS_ALLOWED_ORIGINS settings such as:

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

HOWEVER allowing requests from a null origin can introduce potential security concerns, as it opens up your Django application to requests from any source, including local file systems and potentially malicious origins.

What I should have been doing is placing my test.html into the djagno folder and accessing it via http://127.0.0.1:8000/test.html instead.

Goomblepop
  • 41
  • 7