I've created a react app with node backend and recently ran the npm run build command on it.
when served, I noticed the fetch request sent from my frontend don't work properly and actually just respond with the index.html file in my frontend>public folder for no reason.
I'll try to add info that might be relevant.
In my package.json (the one that's in the frontend folder):
"proxy":"http://localhost:3000",
"scripts": {
"start": "set PORT=3001 && react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
In index.js (server side)
const PORT = process.env.PORT || 3000;
app.use(cors({
origin: 'http://localhost:3001',
credentials: true,
}));
an example of a post definition on the server:
app.post("/user/login", (req, res) => {
login(req, res)
});
and the request itself:
const requestOptions = {
method: 'POST',
headers: { 'accept': 'application/json', 'Content-Type': 'application/json' },
body: JSON.stringify({ "email": email, "password": password }),
credentials: 'include'
};
//HTTP://localhost:3000
fetch(`/user/login`, requestOptions).then(response => {
if (response.status == 200) {
console.log(document.cookie.split("=")[1])
setToken(document.cookie.split("=")[1]);
console.log("here")
}
else {
setError(true)
response.json().then((data) => {
setMessage(data.msg)
console.log(data.msg)
})
}
})
The request's status gives 200 and the respond is always the content of index.html . the request URL as shown on my browser is http://localhost:3000/user/login.
When I run the app with npm start and nodemon, everything works fine.
Only when I try to serve the build it stops working as it should.
Any idea what could be the problem?
Related
Everything works fine on local machine, Please let me if my server setup is correct
Project Structure
/client/--React frontend app
/client/package.json
/index.js
/package.json -- express server
In My /index.js
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const path = require("path");
const app = express();
app.use(cors());
app.use(express.json());
if (process.env.NODE_ENV === "production") {
app.use(express.static("client/build"));
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, "client", "build", "index.html"));
});
}
app.listen(process.env.B_PORT || 5000, () => {
console.log(`Express server Up and Running - Port : ${process.env.B_PORT}`);
});
In My /client/package.json
{
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"proxy": "http://localhost:5000",
}
I am getting 405 not allow for post request, but when i do http://myec2ip:5000 i can json response from express.
What config am i missing ?
You will need to open port 5000 in security group setting of ec2 and allow anyone to access it using 0.0.0.0 for incoming connections.
This might be marked as a duplicate but I looked at all the Stack Overflow posts on this topic. I also listed some of them below. Many of the posts on this topic also didn't have a correct answer "ticked".
I have a React app that I wish to connect to a Node server using Express. It is the first time I do this so I followed this post https://www.twilio.com/blog/react-app-with-node-js-server-proxy. I followed all the instructions, as far as I can see, I have checked several times. So I went and did research to see if I can figure out what the problem is.
When I run npm run dev to start up both the sever and the React app, the React app shows correctly in my browser. However when I type my name in the textbox I get the following error in my terminal:
[HPM] Error occurred while trying to proxy request /api/greeting?name=Johnnie from localhost:3000 to http://localhost:3001/ (ECONNREFUSED) (https://nodejs.org/api/errors.html#errors_common_system_errors)
In my console on the front-end I get:
VM92:1 GET http://localhost:3000/api/greeting?name=Johnnie 504 (Gateway Timeout)
Uncaught (in promise) SyntaxError: Unexpected token E in JSON at position 0
Fetch failed loading: GET "http://localhost:3000/api/greeting?name=Johnnie.
I did hours of research and followed some instructions on the following StackOverflow posts:
React Js: Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0
Fetching JSON returns error Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0 and status code 304: Not Modified
fetch gives response Unexpected token < in JSON
"React Proxy error: Could not proxy request /api/ from localhost:3000 to http://localhost:5000 (ECONNREFUSED)'? Error.. No solution online
……and more
I added a setupProxy.js file too.
Here is my package .json snippet:
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"server": "node-env-run server --exec nodemon | pino-colada",
"dev": "run-p server start"
},
"proxy": "https://localhost:3001/",
My .env
REACT_APP_API_URL=http://localhost:3001
setupProxy.js
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use(createProxyMiddleware("/api/*", { target: "http://localhost:3001/" }));
};
server/index.js
const express = require('express');
const bodyParser = require('body-parser');
const pino = require('express-pino-logger')();
const PORT = 3001;
const app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(pino);
app.get('/api/greeting', (req, res) => {
const name = req.query.name || 'World';
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ greeting: `Hello ${name}!` }));
});
app.listen(3001, () =>
console.log('Express server is running on localhost:3001')
);
The handleSubmit function in App.js
handleSubmit(event) {
event.preventDefault();
fetch(`/api/greeting?name=${encodeURIComponent(this.state.name)}`)
.then(response => response.json())
.then(state => this.setState(state));
}
I know the issue has to do with the server and app not running concurrently but I don't know what could be wrong.
You can find solution from here
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.
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
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!'})
})
[1] https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request
[2] https://www.npmjs.com/package/cors
Parameters are set and once button is pressed, a request [Node request package] or fetch request is made to be received by expressjs request. While link address is created, response returned is 400 Bad Request.
I've tried both a fetch request and a node package 'request' and
Server JS
const express = require ('express');
const path = require('path') //core node module
const app = express();
const cors = require('cors');
const router = express.Router();
// app.use(cors())
const publicdirpath = path.join(__dirname, '../public')
console.log(path.join(__dirname, '../public'))
app.use(cors());
app.use(express.static(publicdirpath))
app.post('/testcall', (req, res) => {
if(!req.query.startdate && !req.body.enddate &&
!req.body.projectnumber){
return res.status(400).send({
success: 'false',
message: 'dates or project or both required'
});
}
//call stored procedures
});
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
JS Class that calls express JS
handleDropdownClick = (event, selection) =>{
const { name, innerText, value } = event.target;
console.log( event.target + " : " + innerText + " : " +
this.props.formData);
const request = require('request');
switch(selection){
case 1:
//call api or stored procedure
if(this.validation()){
//call api
request.get({url:"http://localhost:3000/testcall", qs:this.state.formData} , function (err, res, body) {
if(err){
console.error('error with request: error: ' + err + '. res: ' + res + ' + body: ' + body);
}
console.log("Get response: " + res.statusCode + ". Body: " + body);
})
//Using Fetch
const jsonData = JSON.stringify(this.state.formData);
fetch('/testcall', {
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'credentials': 'include'
},
body: jsonData
})
.then( response => {
return response.json();
})
.then( response => {
console.log(response);
})
.catch(function (e) {
console.log("fail: " + e);
})
}
break;
//more code
Package.json
{
"name": "app-name",
"version": "0.1.0",
"private": true,
"main": "index.js",
"dependencies": {
"body-parser": "^1.19.0",
"cors": "^2.8.5",
"express": "^4.17.1",
"nodemon": "^1.19.1",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-scripts": "3.0.1",
"request": "^2.88.0",
"save": "^2.4.0",
"semantic-ui-react": "^0.87.2",
"table": "^5.4.1",
"tedious": "^6.2.0",
"webpack": "^4.29.6"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"dev": "run-p server start"
},
"eslintConfig": {
"extends": "react-app"
},`enter code here
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"proxy":"http://localhost:3000"
}
Index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
serviceWorker.unregister();
File Path
public
src
-api
-components
-storedprocedures
-tabs
-app.js
-config.js
-index.js
-server.js
package-lock.json
package.json
Expected results would be for the expressjs to accept the call and complete logic.
Actual results are:
POST http://localhost:3000/calculatecommission 400 (Bad Request)
- for the npm package request
request.js:149 GET http://localhost:3000/calculatecommission?projectnumber=&startdate=2019-06-02&enddate=2019-06-28 400 (Bad Request)
- for fetch request
You can use axios or use proxy at front-end
I would recommend using Axios as well, it's a whole lot easier to use then fetch. You can find out more here
https://alligator.io/react/axios-react/
Got the same result with axios unfortunately. I'm wondering if the issue is that the express is server file is set up wrong. Maybe it's not getting the request at all.
request.js:149 GET http://localhost:3000/calculatecommission?projectnumber=&startdate=2019-06-02&enddate=2019-06-28 400 (Bad Request) - for fetch request
Any time you get an error like this, don't forget, you are literally allowed to run this command yourself in the command-line interface. That will give you the exact error that the install script is actually running into, i.e.:
GET https://www.google.com/
In my case, the error was: HTTPS not supported without installing LWP::Protocol::https.
So:
I resolved all of the issues from the GET command.
Since the network it was trying to access was private, I used sudo npm install --s.
So I tried integrating Stripe into React and it required setting up a node js express server.
The server is well set up and returns build folder of react when deployed to Heroku by some changes I made to my package.json and a new server.js file I wrote.
// package.json
{
...
"scripts": {
"dev": "react-scripts start",
"start": "node server.js",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject",
"heroku-postbuild": "yarn run build"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
],
"proxy": "http://localhost:9000",
"engines": {
"node": "10.15"
}
}
// server.js
const express = require("express");
const app = express();
const path = require("path")
const cors = require("cors")
app.use(express.static(path.join(__dirname, 'build')));
app.use('/charge', express.json());
// app.use(cors())
let whitelist = ['localhost:9000', 'http://myapp.herokuapp.com', 'http://herokuapp.com']
let corsOptions = {
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
}
}
app.post("/charge", cors(corsOptions), async (req, res) => {
try {
let {amount, tokenId, stripe_key, company_name} = req.body; // params sent in with client
const stripe = require("stripe")(stripe_key); // initializes stripe with the stripe keys passed from client
// console.log(amount, tokenId, stripe_key);
let description = `Payment for posting for ${company_name} on MyApp.io`
let {status} = await stripe.charges.create({
amount,
currency: "usd",
description,
receipt_email: 'emeruchecole9#gmail.com',
source: tokenId
});
console.log(status);
res.json({status});
} catch (error) {
// res.status(500).end();
res.json({error}).end();
console.log(error)
}
});
app.get('*', (req,res) =>{
res.sendFile(path.join(__dirname+'/build/index.html'));
});
app.listen(process.env.PORT || 9000, () => console.log("Listening on port 9000"));
I have a Checkout.js file that handles the stripe payment. It sends the generated token to the express server.
The part of the Checkout.js file that sends the POST data to the server is:
axios({
method: 'post',
url: '/charge',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
data: {
amount: amount*100 || 2000, //this should be dynamic and coming from price of selected tier in tier selection plan
tokenId,
stripe_key,
company_name: company_name || 'Test Inc.'
}
})
The issue is this:
This totally works in dev mode (when I run yarn run dev and then node server.js to fire up the server) and also when I run yarn run build to manually build and yarn run start which fires up the server and serves the build file according to the server.js file above.
But after deploying to heroku and trying the post action, I get a 405 Not Allowed Error. I have tried adding CORS as seen in the server file above but it did not work.
Did you try to add the cors middleware to express
Like
app.use(cors())
Just Add Below code first of your server.js
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
i hope this code help you,it was helpful for me.
also you can read this article:
clickme:)