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??
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