skip to Main Content

I am developing a simple application using Flask for the backend and React for the frontend. When I try to start my React application using npm start, I encounter a CORS error. However, when I use HOST=127.0.0.1 npm start, the application runs successfully without any CORS error.

Here is the code snippet for the Flask application:

#!/usr/bin/env python3

from flask import Flask
from flask_cors import CORS
from os import environ

try:
    origins = environ["ORIGINS"]
except KeyError:
    kwargs = {}
else:
    if "," in origins:
        origins = origins.split(",")
    kwargs = dict(resources={r"/*": dict(origins=origins)})

print(kwargs)

app = Flask(__name__)
CORS(app, **kwargs)


@app.route("/")
def index():
    return "reachedn"


if __name__ == "__main__":
    app.run(port=5000)

Here is the code snippet for the React application:

import React, { useEffect, useState } from 'react';

const localhost = window.location.hostname

function App() {
  const [response, setResponse] = useState('');

  useEffect(() => {
    document.title = localhost
    fetch(`http://${localhost}:5000/`)
      .then((response) => {
        if (!response.ok) {
          throw Error('Network response was not ok');
        }
        return response.text();
      })
      .then((data) => setResponse(data))
      .catch((error) => console.log(error));
  }, []);

  return (
    <div>
      <h2>"reached" expected:</h2>
      <p>{response}</p>
    </div>
  );
}

export default App;

I am using the hostname dynamically from window.location.hostname for the fetch URL. Does anyone know why specifying the host as 127.0.0.1 resolves the CORS error, while just using npm start does not?

2

Answers


  1. Chosen as BEST ANSWER

    I’ve Resolved It Myself

    Method of Investigation

    With the help of ChatGPT, I created the following program:

    #!/usr/bin/env python3
    # clnt.py
    
    import requests
    from os import environ
    
    LOCALHOST = environ.get("LOCALHOST", "127.0.0.1")
    
    headers = {
        "Origin": f"http://{LOCALHOST}:3000",
    }
    
    response = requests.get(f"http://{LOCALHOST}:5000", headers=headers)
    
    print("Status Code:", response.status_code)
    print("Response Content:", response.content)
    print("Response Headers:", response.headers)
    

    I simplified the Flask program as follows:

    #!/usr/bin/env python3
    # serv.py
    
    from flask import Flask
    from flask_cors import CORS
    
    app = Flask(__name__)
    CORS(app)
    
    
    @app.route("/")
    def index():
        return "reachedn"
    
    
    if __name__ == "__main__":
        app.run(port=5000)
    

    Then, I tried the following:

    #!/bin/bash
    
    ./serv.py &
    serv=$!
    sleep 1
    ./clnt.py
    LOCALHOST=localhost ./clnt.py
    kill $serv
    

    As a result, the above script output:

    127.0.0.1 - - [26/Sep/2023 18:03:21] "GET / HTTP/1.1" 200 -
    Status Code: 200
    Response Content: b'reachedn'
    Response Headers: {'Server': 'Werkzeug/2.3.7 Python/3.9.6', 'Date': 'Tue, 26 Sep 2023 09:03:21 GMT', 'Content-Type': 'text/html; charset=utf-8', 'Content-Length': '8', 'Access-Control-Allow-Origin': 'http://127.0.0.1:3000', 'Vary': 'Origin', 'Connection': 'close'}
    Status Code: 403
    Response Content: b''
    Response Headers: {'Content-Length': '0', 'Server': 'AirTunes/695.5.1'}
    

    It seems that the AirTunes server was using port 5000.

    Solution

    I modified clnt.py and serv.py so that the port could be variable:

    PORT=5001 ./serv.py &
    serv=$!
    sleep 1
    PORT=5001 ./clnt.py
    PORT=5001 LOCALHOST=localhost ./clnt.py
    kill $serv
    

    As a result, I obtained the expected output:

    127.0.0.1 - - [26/Sep/2023 18:03:23] "GET / HTTP/1.1" 200 -
    Status Code: 200
    Response Content: b'reachedn'
    Response Headers: {'Server': 'Werkzeug/2.3.7 Python/3.9.6', 'Date': 'Tue, 26 Sep 2023 09:03:23 GMT', 'Content-Type': 'text/html; charset=utf-8', 'Content-Length': '8', 'Access-Control-Allow-Origin': 'http://127.0.0.1:3000', 'Vary': 'Origin', 'Connection': 'close'}
    127.0.0.1 - - [26/Sep/2023 18:03:23] "GET / HTTP/1.1" 200 -
    Status Code: 200
    Response Content: b'reachedn'
    Response Headers: {'Server': 'Werkzeug/2.3.7 Python/3.9.6', 'Date': 'Tue, 26 Sep 2023 09:03:23 GMT', 'Content-Type': 'text/html; charset=utf-8', 'Content-Length': '8', 'Access-Control-Allow-Origin': 'http://localhost:3000', 'Vary': 'Origin', 'Connection': 'close'}
    

    The front-end and back-end programs presented in the original question started working as expected after changing the port from 5000 to 5001 (provisionally).


  2. ‘npm start’ will typically start your server on http://localhost:3000 instead of http://127.0.0.1:3000 unless you specify the host. Since your backend app runs on HOST http://127.0.0.1, which is a different host from http://localhost which the react app is running, the cors middleware is blocking the request. Cross-origin requests are subject to the same-origin policy, which restricts web pages from making requests to a different origin (host, protocol, or port) unless the server explicitly allows it using CORS headers.

    In this case, you’d observe that all is well when you specify the host when starting the react app as http://127.0.0.1 because the host is of same origin with that of the flask app and doesn’t violate the CORS policy.

    To resolve this you will have to modify your flask code to allow request from http://localhost origin, which will look like this

    #!/usr/bin/env python3
    
    from flask import Flask
    from flask_cors import CORS
        
    app = Flask(__name__)
    
    CORS(app, resources={r"/api/*": {"origins": "http://localhost"}}) #allow on same origin and http://localhost
    
    
    @app.route("/")
    def index():
        return "reachedn"
    
    
    if __name__ == "__main__":
        app.run(port=5000)
    

    OR like this if you want to allow from all origins (any host)

    #!/usr/bin/env python3
    
    from flask import Flask
    from flask_cors import CORS
        
    app = Flask(__name__)
    
    CORS(app, resources={r"/api/*": {"origins": "*"}}) #allow all origins
    
    
    @app.route("/")
    def index():
        return "reachedn"
    
    
    if __name__ == "__main__":
        app.run(port=5000)
    

    I hope this helps. Cheers.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search