reactjsdjangonginxcorsdjango-cors-headers

Django CORS error in media file | Nginx | React


I am trying to fetch image from my django server from my react app. Tried multiple configuration but nothing to rescue. It would be great if anyone could provide any insight or leads or something I am missing

React

Using react behind nginx (on client machine) so origin is always http://127.0.0.1 instead of http://localhost:3000

import axios from "axios"
export async function getImageFromNginx() {
        const IMAGE_URL = "http://{SERVER_URL}/media/pages/64d3d8cb4d3bd545823595e4.png"
        const config = {
                mode: 'cors', // no-cors, *cors, same-origin
        headers: {
                  'Access-Control-Allow-Origin' : 'http://127.0.0.1',
                  'Access-Control-Allow-Credentials': 'true',
         },
         auth: {'username': 'username', 'password':'password'},
         withCredentials: true,
}
console.log(config)
try{
         const response = await axios.get(IMAGE_URL, config).then((res)=>console.log("in axios",res))
         console.log('Call to Nginx')
         return await response.json();
}catch(error) {
         return [];
}

}

Django

in django settings for cors, have installed django-cors-headers and added app and middleware settings

CORS_ALLOWED_ORIGINS = ['http://127.0.0.1']
CORS_ALLOW_CREDENTIALS = True    
CORS_ALLOW_HEADERS = ['Content-Type', 'Access-Control-Allow-Origin']    
CORS_ALLOW_METHODS = ['GET', 'POST', 'OPTIONS']

Django Method to serve file using nginx (on server)

def send_file(roots, file_name, disposition_type=None,

default_file_name=None):



    valid = ['/download/{}'.format(root) for root in roots \
    
            if os.path.exists(get_absolute_filename(root,file_name))]
    
    if valid:

           response = HttpResponse()
    
           response['Content-Type'] = ''
    
           if disposition_type is not None:
    
                 end_user_filename = default_file_name and default_file_name or file_name
    
                 response['Content-Disposition'] = "{}; filename={}".format(
    
                              disposition_type, end_user_filename)
    
                  response['X-Accel-Redirect'] = os.path.join(valid[0], file_name)
    
                  response['Access-Control-Allow-Origin'] = 'http://127.0.0.1/'
    
                  response['Access-Control-Allow-Methods'] = 'GET'
    
                  response['Access-Control-Allow-Headers'] = 'Content-Type, Access-Control-Allow-Origin'
    
                  response['Access-Control-Allow-Credentials'] = 'true'
    
    else:
    
          response = HttpResponseNotFound("Requested file is not available")
    
    return response

Nginx configuration on server

CORS Related snippets

location /download/

{

        alias /media/;

        internal;

        add_header 'Access-Control-Allow-Origin' 'http://127.0.0.1/' always;

        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;

        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Access-Control-Allow-Origin' always;

        add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;

        add_header 'Access-Control-Allow-Credentials' 'true';

}


location / {

if ($request_method = 'OPTIONS') {

add_header 'Access-Control-Allow-Origin' 'http://127.0.0.1/';

add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';

#

# Custom headers and headers various browsers *should* be OK with but aren't

#

add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Access-Control-Allow-Origin';

#

# Tell client that this pre-flight info is valid for 20 days

#

add_header 'Access-Control-Max-Age' 1728000;

add_header 'Content-Type' 'text/plain; charset=utf-8';

add_header 'Content-Length' 0;

add_header 'Access-Control-Allow-Credentials' 'true';

return 204;

}

if ($request_method = 'POST') {

add_header 'Access-Control-Allow-Origin' 'http://127.0.0.1/' always;

add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;

add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Access-Control-Allow-Origin' always;

add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;

add_header 'Access-Control-Allow-Credentials' 'true';

}

if ($request_method = 'GET') {

add_header 'Access-Control-Allow-Origin' 'http://127.0.0.1/' always;

add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;

add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Access-Control-Allow-Origin' always;

add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;

add_header 'Access-Control-Allow-Credentials' 'true';

}

}

}

Solution

  • It's a common problem when you try to use django and react on the different domains.

    You don't need to play with CORS here.

    The best practice is to resolve it by nginx.

    server {
        listen 80;
        server_name yourdomain.com;
    
        # Serve React static files
        location / {
            # Point this to the directory where your React build outputs its static files.
            root /path/to/react/build;
            try_files $uri /index.html;
        }
    
        # Proxy requests to Django backend
        location /backend/ {
            # Point this to the IP and port where your Django app is running.
            # If Django runs on the same server, you can use localhost or 127.0.0.1.
            proxy_pass http://localhost:8000;
    
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
    
            # Handle WebSockets
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }
    }
    

    So, both apps will work on the same url, and won't have ny problems with cors.