skip to Main Content

I have a frontend react that uses axios to get data from a separate node server. The frontend uses a .app domain with SSL certificate but the backend http://localhost:3001, vanilla http, IP address, and port.

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

axios({
        method: 'GET',
        url: 'http://localhost:3001/',
        params: {page: pageNumber, limit: limit},
        cancelToken: new axios.CancelToken(c => cancel = c)
    }).then( res => {
        setSermons( prevSermons => {
            return [...new Set([...prevSermons, ...res.data.map( sermon => sermon )])]
    })
        setHasMore(res.data.length > 0)
        setLoading(false)
    }).catch( e => {
        if (axios.isCancel(e)) return
        setError(true)
    })
    return () => cancel()
}, [query, pageNumber, limit] )

… and here is my backend node/express server:

const express = require('express')
const cors = require('cors')
const knex = require('knex')
require('dotenv').config()

const db = knex({client: 'pg', connection: <...connection stuff...>})
const app = express()
app.use(express.urlencoded({ extended: false }))
app.use(express.json())
app.use(cors())

app.get('/', (req, res) => {
    let page = req.query.page || 0
    let limit = req.query.limit || 50
    db.select('*')
        .from('sermons')
        .limit(limit, {skipBinding: true})
        .offset(limit*page)
        .then( (data) => {
            res.json(data)
        })
        .catch( (err) => {
            console.log(err)
        })
})

const port = process.env.APP_PORT   
app.listen(port, '0.0.0.0', () => console.log(`Server running on port ${port}, http://localhost:${port}`));

I can open both the frontend and backend parts of the site on my browser. The backend is accessible via http://157.xxx.xxx.xxx:3001 IP and the frontend maps to my domain. But the frontend can’t retrieve data from the backend.

All of this is running behind an nginx reverse proxy. I did not find any firewalls installed on the server. Yesterday it was working but overnight the connection refused error started. I know that previously, I left the localhost out of the nginx setup entirely.

It seems like CORS is not working, even though the node server is importing/using it. What more can I look at to debug this?

3

Answers


  1. Chosen as BEST ANSWER

    Turns out I couldn't get the backend server to work with http://localhost:3000 but it did work if I mapped it to a true external API with https. This is the final configuration that worked:

    nginx.conf file for JUST the backend server. Previously it was absent from nginx.conf because I was trying to make it a localhost only endpoint.

        server {
            listen 443 ssl; # using port 3000 wont work on some wifi, so incoming is 443 (ssl)
            # server_name 157.xxx.xxx.xxx; # gets blocked because mixed content http / https
    
            server_name <app.mydomain.com>;
            ssl_certificate /etc/letsencrypt/live/<app.mydomain.com>/fullchain.pem;
            ssl_certificate_key /etc/letsencrypt/live/<app.mydomain.com>/privkey.pem;
    
            location / {
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $host;
                proxy_pass http://127.0.0.1:3001;       #<--- react-backend server listens on this port
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
            }
        }
    

    How the frontend react app uses axios to talk to backend. The backend endpoint is now HTTPS, with a separate, valid SSL certificate for that the <api.mydomain.com> subdomain:

    axios({
           method: 'GET',
           mode: 'cors',
           url: 'https://api.<mydomain.com>',
           params: {page: pageNumber, limit: limit}, // { q: query, page: pageNumber },
    

    changes to my node/express backend server endpoint

    const express = require('express')
    const knex = require('knex')
    require('dotenv').config()
    const cors = require('cors')
    var corsOptions = {
       origin: '*',
       optionsSuccessStatus: 200
    }
    app.use(cors(corsOptions))
    
    const db = knex({...config stuff})
    
    app.get('/', (req, res) => {
        db.select(... --> ...res.data)
        res.setHeader('Acess-Control-Allow-Origin', '*');
    })
    const port = process.env.APP_PORT
    app.listen(port, '0.0.0.0', () => console.log(`Server running on port ${port}, http://localhost:${port}`));
    

    I think many of these changes were not needed, but this is a working state, over https.

    Next I'll see if I can block access to this backend to everyone except the frontend domain.


  2. try adding "proxy": "http://localhost:3001" to your package.json

    it will proxy your backend and resolve CORS issues. You can read more about it in this blog post:

    https://medium.com/bb-tutorials-and-thoughts/react-how-to-proxy-to-backend-server-5588a9e0347

    Login or Signup to reply.
  3. it does sound like a Cors problem
    here is a quick video explaining on how cors works

    https://www.youtube.com/watch?v=4KHiSt0oLJ0&ab_channel=Fireship

    try adding a proxy in the package.json or set a header like this

    res.setHeader('Access-Control-Allow-Origin', '*');
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search