Search code examples
javascriptreactjsflasknpmcors

Why does npm start fail due to CORS error, but HOST=127.0.0.1 npm start succeed?


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 "reached\n"


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?


Solution

  • 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 "reached\n"
    
    
    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'reached\n'
    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'reached\n'
    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'reached\n'
    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).