Reputation: 863
The issue I am having is my React application hosted on Heroku is calling "https://localhost:8000" for it's calls to the Express server.
I have the proxy
in package.json
set to https://localhost:8000
to call my Express server. From my understanding this is all I need to do and Heroku handles the connection when it is deployed.
When I go to my endpoint like so: https://heroku-app.herokuapp.com/v1/products/:productid
my Express server successfully sends back JSON data in the browser, so I do know my Node server is up and running on Heroku. The issue seems to be the React app proxy
is not calling the Heroku URL post-deploy.
Here is my React apps package.json
:
{
"name": "client",
"version": "0.1.0",
"private": true,
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
],
"proxy": "http://localhost:8000/",
"devDependencies": {
"enzyme-matchers": "^7.0.2"
}
}
This is the package.json
file for my server:
{
"name": "stub_boilerplate",
"version": "1.0.0",
"description": "Quick Stub",
"main": "server.js",
"scripts": {
"test": "jest",
"start": "node server/server.js",
"heroku-postbuild": "cd client && npm install --only=dev && npm install && npm run build"
},
"engines": {
"node": "~9.10.1",
"npm": "~5.6.0"
},
"repository": {
"type": "git",
"url": "git+https://github.com/manm/xxx.git"
},
"author": "Maison M",
"license": "MIT",
"bugs": {
"url": "https://github.com/maonm/xxx/issues"
}
}
Here is my server.js
file. I am setting the port
to process.env.PORT || 8000
:
const express = require('express');
const app = express();
const port = process.env.PORT || 8000;
//Allows access to enviroment variables in development
require('dotenv').config({ path: __dirname + '/.env' });
//Middleware
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(methodOverride('_method'));
//Serve build folder of client
app.use(express.static(path.join(__dirname, '../client/build')));
app.use('/v1/products', product_routes);
//Error handling
app.use(errorHandler);
//Initialize Express server
app.listen(port, err => {
if (err) console.info(`Error: The server failed to start on ${port}`);
else console.info(`****** Node server is running on ${port} ******`);
});
This is the fetch() request inside of the component:
componentDidMount() {
this.fetchStripePlans();
}
fetchStripePlans = () => {
const stripeProduct = 'prod_FlXXXXXBVn8'; //QS (product)
const url = `http://localhost:8000/v1/products/${stripeProduct}`;
const fetchConfig = {
method: 'GET',
headers: {
'content-type': 'application/json'
}
};
fetch(url, fetchConfig)
.then(data => data.json())
.then(stripe => {
const { data } = stripe;
this.setState({
stripePlans: data
});
})
.catch(err => {
this.setState({
error: true,
errorMessage: err.genericError
});
});
};
This is what I am seeing in the console of the React app:
SignUpContainer.js:48 OPTIONS http://localhost:8000/v1/products/prod_FRon8 net::ERR_CONNECTION_REFUSED
So to me logically, it's not being routed to the Heroku URL. I've scoured a few tutorials on deploying React/Express projects to Heroku and all of them leave the React proxy
set to the local host of the Express server. So I am not too sure what is happening here.
Upvotes: 0
Views: 4382
Reputation: 4125
In order to make use of the proxy
value in your package.json
, you must specify a relative URL in your fetch request, such as /v1/products/${stripeProduct}
. You should not include the hostname or port in your component.
For reference, see "Running the server and the React app" and "Using the proxied server from React" sections in here: https://www.twilio.com/blog/react-app-with-node-js-server-proxy
Upvotes: 1
Reputation: 1310
Although a GET request usually qualifies as a simple request, the fact that the Content-Type is set as application/json qualifies it as a pre-flight [1] request. Therefore, what happens is that the browser sends a HTTP request before the original GET request by OPTIONS method to check whether it is safe to send the original request.
Try enabling CORS Pre-Flight for your route handler sending the application/json response. You can do this by using the cors [2] middleware in the options handler for your route, like such:
const express = require('express')
cosnt cors = require('cors')
const app = express()
app.options('/products/:id', cors()) // enable pre-flight request for GET request
app.get('/products/:id', cors(), function (req, res, next) {
res.json({msg: 'This is CORS-enabled for all origins!'})
})
Upvotes: 0