Deploying React Express and Node app to Heroku Proxy Error - node.js

I have successfully in the past launched full stack applications to Heroku by using within the client package.json file.
"proxy": "http://localhost:3001"
Now I am getting an "Invalid Host header" I did fix that error by removing the proxy as well as implementing setupProxy.js file with the following code, but afterwards the app does not call the back end at all and errors out.
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
'/api',
createProxyMiddleware({
target: 'http://localhost:3001',
changeOrigin: true,
})
);
};
I'm wondering how to fix, or if anything changed recently in Heroku to not allow proxy within the client package.json file?

It looks like it was a seemingly unrelated fix. I had to enter in some environment variables within Heroku to allow the server to run. Without the variables, I believe the server would stop with errors therefore trickling down and causing many problems. So long story short, always remember your environment variables within Heroku.

Related

Basic express setup: not sending anything to local port

I created a frontend app and now trying to incorporate backend into it.
ON the same frontend app i added an index.js file in the root directory, and installed express and required it in index.js file.
Very basic setup as below:
const express = require('express')
const cors = require('cors')
const port = process.env.PORT || 3001
const app = express()
app.get('/', (req, res) => {
res.send({
greetings: 'hi'
})
})
app.listen(port, () => {console.log(`Server on port ${port}`)})
Server is successfully on port 3001 as per my terminal, however, on localhost:3001 I'm not seeing any json response I set up in app.get.
It says Cannot GET / instead. When i inspected in devtool(Network) it says 404.
This seems a very straightforward setup, but what could've gone wrong here?
i just figured why. I installed nodemon but my “start” script is “node index.js”. Should’ve used “nodemon index.js”
Working now with nodemon index.ks
Your code is fine, There are no errors, I tested it and it works as expected.
However few things to note, Keep Backend in Seperate folder/dirctory unless required.
Coming back to your question, There are many possiblity such as some modules are not installed properly
try running following command
//this will install if any library is currupt or not installed properly
npm i
if it doesn't work then try clearing cache
Also keep in mind, In nodeJS dev server does not automatically refresh changes, you need to restart server to see changes or you can use dev dependancy called Nodemon (this will auto restart server on saving changes)

My CRUD app works locally but not on Heroku

I've created a CRUD app and it works locally, but I can't get it to work fine on heroku. It deploys correctly, the website seems to work, but then I can't get the items I need from the database, as it keeps saying connection refused.
I added the .env variables to Heroku, as well as setting the port to process.env.PORT || 5000 and app.listen(port), I'm not sure what's causing the error. I also have a Procfile with web: node server.js, and a "start" script in package.json that points to server.js. It seems that the server doesn't start at all.
Here the repo in case you want to have a look https://github.com/ThomYorke7/inventory, here the app on heroku https://boardgamenerd.herokuapp.com/
The problem lies in the fact that your application has a backend (server) and a frontend (client) which are served differently locally than on Heroku.
I suppose locally your client is running on localhost:3000 (as it is the default with create-react-app you bootstrapped).
While your backend is running on localhost:5000, your client's package.json contains this line to make it work locally:
"proxy": "http://localhost:5000",
If I visit this page of your app: https://boardgamenerd.herokuapp.com/ > boardgames,
then I face these errors on the browser console:
boardgames-list.jsx:18
Error: Network Error
at e.exports (createError.js:16)
at XMLHttpRequest.p.onerror (xhr.js:83)
xhr.js:178
GET http://localhost:5000/boardgames/ net::ERR_CONNECTION_REFUSED
It tells you that your production version still calls backend on localhost:5000.
I.) First I'd try to fix these fetches by changing to relative URLs.
E.g. the above example (boardgames-list.jsx:18)
❌ your current script has hardcoded localhost fetch at the moment:
useEffect(() => {
axios
.get('http://localhost:5000/boardgames/')
.then((response) => {
setBoardgames(response.data);
setLoading(false);
})
.catch((err) => console.log(err));
}, []);
✔️ make it relative to root by removing "http://localhost:5000":
useEffect(() => {
axios
.get('/boardgames/')
.then((response) => {
setBoardgames(response.data);
setLoading(false);
})
.catch((err) => console.log(err));
}, []);
And it will work on Heroku. In case it wouldn't: see my suggestion below.
II.) Second, a suggestion:
Now your https://boardgamenerd.herokuapp.com/boardgames route uses the following backend endpoint to fetch data: https://boardgamenerd.herokuapp.com/boardgames/
The difference is only the last slash ("/") character which can be confusing and cause more issues later!
It is a best practice to add a differentiator path element to your backend endpoints, like /api/. For example: https://boardgamenerd.herokuapp.com/api/boardgames So you can be sure by first sight which GET request related to the backend and which one to the client.
If you'd go with this solution, you will need to add the following to your server.js:
app.use(express.static(path.join(__dirname, 'client', 'build')))
// required to serve SPA on heroku production without routing problems; it will skip only 'api' calls
if (process.env.NODE_ENV === 'production') {
app.get(/^((?!(api)).)*$/, (req, res) => {
res.sendFile(path.join(__dirname, 'client/build', 'index.html'))
})
}
/^((?!(api)).)*$/ regex skips URLs containing "api" in their path, so they won't be served static as the client/build folder's content - api calls won't be served from static and will work fine.

set proxy in package.json to env variable

I need to set the proxy value in my package.json at runtime, like with an environment variable. How could this be done?
// package.json
{
"name": "demo",
"proxy": process.env.MY_PROXY_VAL , // <- how?
"dependencies": {},
"scripts": {},
}
Thanks.
It will automatically read from HTTPS_PROXY or HTTP_PROXY so you dont need to do that.
From the docs:
A proxy to use for outgoing https requests. If the HTTPS_PROXY or https_proxy or HTTP_PROXY or http_proxy environment variables are set, proxy settings will be honored by the underlying request library.
So I am converting my comment into an answer, since I think it is important to point out an actual solution to this problem.
I was searching for that exact same answer, and also tried setting the HTTP_PROXY and HTTPS_PROXY variables via an .env file, and also directly from within a script. However this does not solve the problem since this will overwrite the system proxy settings for the local machine, which I don't think was something the OP intended to do. The result can be that you cannot load npm packages anymore, because of incorrect system proxy settings.
Instead, there is a way of manually configuring the proxy for a CRA in development, as pointed out by the official docs:
https://create-react-app.dev/docs/proxying-api-requests-in-development/#configuring-the-proxy-manually
With this you should create a local setupProxy.js file under the /src folder of the project, which will then override the proxy set in package.json.
Of course then you have to make sure that all the paths are correctly set, but it works well and you have fine grained control over which pages in your app will be proxied and which will not.
To target specifically your question about how to set the proxy via an environment variable, here is an example how you could do it with the setupProxy approach and the createProxyMiddleware:
// Sample of how to setup a proxy middleware with environment variables
//// file: <project_root>/src/setupProxy.js
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
'/rest',
createProxyMiddleware({
target: process.env.REACT_APP_PROXY_HOST,
changeOrigin: true,
})
);
};
//// file: <project_root>/.env
REACT_APP_PROXY_HOST=https://localhost:6700
In this case I only wanted to proxy requests targeted to the /rest endpoint, for which I created a new endpoint. All other requests will still go to the default localhost:3000 Url, serving the react app.
The host is defined via the environment variable REACT_APP_PROXY_HOST. I defined the variable in the local .env file, but you could also directly set it inside a script in package.json if needed.
Update:
Even though the original question was already solved for me, I had an additional issue trying to forward requests to a server running on https.
The previous development setup has been fine with the static proxy set in package.json. However when using the createProxyMiddleware and targeting a server running on https with certificates, the path to the used certificate has to be provided.
// Sample of how to setup a proxy middleware with environment variables
// targeting a server running on https
//// file: <project_root>/src/setupProxy.js
const { createProxyMiddleware } = require('http-proxy-middleware');
const fs = require('fs');
const protocol = JSON.parse(process.env.HTTPS) ? "https:" : "http:";
const host = process.env.REACT_APP_PROXY_HOST
const port = process.env.REACT_APP_PROXY_PORT
module.exports = function(app) {
app.use(
'/rest',
createProxyMiddleware({
target: {
protocol: protocol,
host: host,
port: port,
pfx: fs.readFileSync('src/root-cert.pem')
},
changeOrigin: true,
})
);
};
//// file: <project_root>/.env
HTTPS=true
REACT_APP_PROXY_HOST=localhost
REACT_APP_PROXY_PORT=6700
In this case instead of providing the target as a string, it should be given as an object containing protocol, host, port and an attribute pfx, which contains the certificate to validate the server via https.
In this case it is a hardcoded path within the project source directory, however it could also be set using environment variables.
The setting HTTPS=true overwrites the default development setup and will by default start the development server at https://localhost:3000.
With this setting as well as providing the correct certificate the server running on https can be reached without issues.
For reference, this solution is officially linked in the documentation of http-proxy-middleware and the underlying node-http-proxy:
https://github.com/chimurai/http-proxy-middleware/blob/master/recipes/https.md
https://github.com/http-party/node-http-proxy#http---https-using-a-pkcs12-client-certificate
This question also got some attention at other places, e.g.
https://github.com/facebook/create-react-app/issues/3783
https://github.com/facebook/create-react-app/issues/4288
https://github.com/usc-isi-i2/kgtk-browser/issues/32
Hope to help someone searching for the same problem, if there are any updates to this or things change feel free to add suggestions in the comments.

node application give proxy error when in production mode

I have a mean.js app which I've deployed to my production server.
it worked well when I had it in development mode, but since I switched it to production mode I'm getting a 502 proxy error.
the same happens whether I run it with node server.js or pm2.
I'm running on linux/debian with apache2.
I a newbie in this environment, how do I find the problem.
It turned out to be an SSL issue.
in my production.js file I commented the following:
module.exports = {
//secure: {
// ssl: false,
// privateKey: './config/sslcerts/key.pem',
// certificate: './config/sslcerts/cert.pem'
//},
...
this is of course a temp solution until the application really goes live

How to setup gulp browser-sync for a node / react project that uses dynamic url routing

I am trying to add BrowserSync to my react.js node project. My problem is that my project manages the url routing, listening port and mongoose connection through the server.js file so obviously when I run a browser-sync task and check the localhost url http://localhost:3000 I get a Cannot GET /.
Is there a way to force browser-sync to use my server.js file? Should I be using a secondary nodemon server or something (and if i do how can the cross-browser syncing work)? I am really lost and all the examples I have seen add more confusion. Help!!
gulp.task('browser-sync', function() {
browserSync({
server: {
baseDir: "./"
},
files: [
'static/**/*.*',
'!static/js/bundle.js'
],
});
});
We had a similar issue that we were able to fix by using proxy-middleware(https://www.npmjs.com/package/proxy-middleware). BrowserSync lets you add middleware so you can process each request. Here is a trimmed down example of what we were doing:
var proxy = require('proxy-middleware');
var url = require('url');
// the base url where to forward the requests
var proxyOptions = url.parse('https://appserver:8080/api');
// Which route browserSync should forward to the gateway
proxyOptions.route = '/api'
// so an ajax request to browserSync http://localhost:3000/api/users would be
// sent via proxy to http://appserver:8080/api/users while letting any requests
// that don't have /api at the beginning of the path fall back to the default behavior.
browserSync({
// other browserSync options
// ....
server: {
middleware: [
// proxy /api requests to api gateway
proxy(proxyOptions)
]
}
});
The cool thing about this is that you can change where the proxy is pointed, so you can test against different environments. One thing to note is that all of our routes start with /api which makes this approach a lot easier. It would be a little more tricky to pick and choose which routes to proxy but hopefully the example above will give you a good starting point.
The other option would be to use CORS, but if you aren't dealing with that in production it may not be worth messing with for your dev environment.

Resources