Reputation: 1828
I created a restful api with django-rest-framework accessible with this URL http://192.168.33.10:8002/scenarios/ and I'm creating a React app to make calls to the api an d consume its data.
I'm using fetch to make calls to the api
componentWillMount: function(){
this.setState({Problemstyle: this.props.Problemstyle})
fetch('http://192.168.33.10:8002/scenarios/')
.then(result=>result.json())
.then(result=> {
this.steState({items:result})
})
},
when i run my app i get an error in my browser
Fetch API cannot load http://192.168.33.10:8002/scenarios/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://192.168.33.10:8001' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
I'm not sure on how to solve this problem as i'm just starting to use React
Upvotes: 22
Views: 42777
Reputation: 1
I faced the same problem even after installing all the cors module for django and writing all the cors statements in the settings.py.
HTTP 401 Unauthorized
Allow: GET, HEAD, OPTIONS Content-Type: application/json Vary: Accept
{ "error": "Authentication required to fetch groups." }
The problem was "Authentication" field in the request header. The token should be added with authorization.
const response = await axios.get(`${BASE_URL}api/groups/`, {
headers: {
"Authorization": `Token ${token}`, // Include the token in the headers
"X-Username": user.username,
"X-CSRFToken": csrfToken,
"Content-Type": "application/json",
},
withCredentials: true,
});
This worked for me.
Upvotes: 0
Reputation: 1
Placing the corsheaders.middleware.CorsMiddleware
above other middleware configurations fixed it for me.
Placing the corsheaders.middleware.CorsMiddleware
just below the security middleware ensures corsHeaders are added to responses before they reach other middleware
Upvotes: 0
Reputation: 43
django-cors-headers
but are still getting an error such as:Access to XMLHttpRequest at 'http://127.0.0.1:8000/' from origin 'http://localhost:5173' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Well, the problem, at least in my case, was that django-cors-headers
did not recognize http://localhost:5173
for some reason. As we know localhost has the IP address 127.0.0.1
. So I changed the host address of my react server to explicitly use the IP address 127.0.0.1
. I was using react with vite so I did the following changes in my vite.confing.ts
to set a new domain:
export default defineConfig({
// ...
server: {
host: '127.0.0.1', // Set the host to 127.0.0.1
port: 5173, // Set the port to 5173
},
})
So the domain of my frontend server after that will be http://127.0.0.1:5173
.
Now you only have to add this new domain to CORS_ALLOWED_ORIGINS
in settings.py
and the error should be resolved.
CORS_ALLOWED_ORIGINS = [
'http://127.0.0.1:5173',
]
Further information for context:
http://localhost:5173
and http://127.0.0.1:5173
try starting your frontend server using each of them and each time check how the system represents these domains behind the scene using the cmd command netstat -ano
.Upvotes: 0
Reputation: 11
I had the same problem, It was quite funny I was getting 200 code and swagger was working correctly, but react didn't work properly. simply these require in the setting.py:
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
and for front:
const setCookie = async () => {
axios.get(`${process.env.REACT_APP_API_URL}/core/csrf-cookie/`, {
headers: { 'Authorization': null },
withCredentials: true,
}
).catch( () => {
console.log('Something went wrong!')
});
setCsrfToken(getCookie('csrftoken'))
console.log(csrfToken)
}
call setCookie in the useEffect and it should work.
and Don't forget to build react and set STATICFILES_DIRS
Upvotes: 0
Reputation: 9245
Please Note: This solution is not for production configuration. This is merely a workaround for easier setup while development. Please refrain from using this in production configuration.
Install django-cors-headers through pip install django-cors-headers
Then, add in installed apps 'corsheaders'.
Add the setting,
CORS_ORIGIN_ALLOW_ALL = True
and,
ALLOWED_HOSTS = ['*']
This should do the trick.
UPDATE
You'll also need to add it to the middlewares,
MIDDLEWARE = [ # Or MIDDLEWARE_CLASSES on Django < 1.10
...
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
...
]
Upvotes: 34
Reputation: 1745
Just add to the package.json
file the following line:
"proxy": "http://localhost:8000"
Based on Joe Sadoski's great idea,
I suggest an improvement to his solution that also supports react hot-reload-on-changes:
(All other proposed solutions here do not work in chrome since the last upgrades in 2022)
version: '3.1'
services:
web:
image: nginx:latest
ports:
- 8080:80
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
command: [nginx-debug, '-g', 'daemon off;']
environment:
- NGINX_HOST=localhost
- NGINX_PORT=80
network_mode: host
restart: unless-stopped
My change here is: network_mode: host
Now the nginx.conf
looks like this:
events {}
http{
server {
listen 80;
server_name localhost;
// this block handle react hot-reload
location /sockjs-node {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
// this block handle API calls
location ~* /(accounts|api|admin) {
proxy_pass http://localhost:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
// this block handle all the rest (react/statics...)
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
Here I change the upstreams to point on localhost
so both react server and django should run on the host computer in ports 3000
and 8000
.
So, after docker-compose up
, manage.py runserver
, and npm start
, both apps are available at http://localhost
!
Upvotes: 2
Reputation: 676
See Yinon_90's answer for a better working version of this concept.
I wanted to propose a solution that does not require altering the behavior of the Django or React apps.
In production, you might want to serve both apps on the same domain/from the same server, under different paths. This wouldn't cause any CORS conflict in production.
Of course, we want to debug Django and utilize React HMR & Dev tools while debugging. For this, I've spun up an nginx docker container:
docker-compose.yml
:
version: '3.8'
services:
web:
image: nginx:latest
ports:
- 8080:80
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
command: [nginx-debug, '-g', 'daemon off;']
environment:
- NGINX_HOST=localhost
- NGINX_PORT=80
nginx.conf
:
Django debug is on port 8000, React HMR is on port 3000. I've allowed three paths to go to the Django app, /accounts
, /api
, and /admin
. The rest goes to the React app (and into the React Router system)
events {}
http{
server {
listen 80;
server_name localhost;
location ~* /(accounts|api|admin) {
proxy_pass http://host.docker.internal:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location / {
proxy_pass http://host.docker.internal:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
After docker-compose up
, manage.py runserver
, and npm start
, both apps are available at localhost:8000
!
Upvotes: 1
Reputation: 116
Using django-cors-headers
Start by installing django-cors-headers using pip
pip install django-cors-headers
You need to add it to your project settings.py file:
INSTALLED_APPS = (
##...
'corsheaders'
)
Next 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 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',
)
Upvotes: 4
Reputation: 6835
The currently accepted answer potentially opens sites up to security risks:
In order for your AJAX request to work well, there are two things that need to happen:
The error that the OP reports, indicates that the second part of this process is failing. This is because if the request is sent from domain that is different to the server returning the request, the browser won't accept it unless the appropriate headers are set (that is, the server has given permission for the browser to read it).
Now to fix this, we can use django-cors-headers
. This will add the apropriate headers, so that the browser accepts the returned response. To install run:
pip install django-cors-headers
and add it to your middleware:
MIDDLEWARE = [
...
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
...
]
Now, you need to add the domain you are sending your AJAX request from, to the list of allowed domains:
CORS_ALLOWED_ORIGINS = [
"www.example.com",
"http://127.0.0.1:8000",
...
]
CORS_ORIGIN_ALLOW_ALL
?Do not use this unless you have a specific need to. Setting this to true, will mean that, any origin will be able to make a request to your API, and get a response. Unless you are making a public API, you probably won't need to do this. More likely you will only need to serve a single domain or a few domains (maybe you have a front-end, served from a different place to your API etc.)
If you are happy for any domain to access your API then you can set the following:
CORS_ORIGIN_ALLOW_ALL = True
If you do this, you will also need to set the following:
ALLOWED_HOSTS = ['*']
The reason for this, is Django will only accept certain hosts by default, so there's no point setting CORS_ORIGIN_ALLOW_ALL = True
unless you're actually going to accept requests from anyone (that is the part 1 in the explanation above).
Note that by setting allowed hosts to a wildcard, you open yourself up to HTTP host header attacks. Make sure you understand these, and have made sure you are not affected. You can read more about them in the django docs.
Also note: if you have not set your ALLOWED_HOSTS
and you are wondering why your requests are working, it is because when DEBUG=True
certain hosts are allowed automatically, http://127.0.0.1:8000
etc.
Upvotes: 25