Error occurred while trying to proxy request (ECONNREFUSED) - node.js

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

Related

Server returned nothing (no headers, no data) when attaching socket.io

I'm using node.js 16 with es6 support enabled and express js,
import express from 'express'
import http from 'http'
const app = express()
app.get('/health', (_req, res, _) => {
console.log('health check')
res.sendStatus(200)
},
const server = http.createServer(app)
server.listen(
8000, '127.0.0.1'
)
here everything works fine, sending get request on
localhost:8000/health return 200
But when I attach socket.io to my HTTP server
I get the following error
Server returned nothing (no headers, no data)
I added socket.io like so
import { Server } from 'socket.io'
onst io = new Server()
io.attach(server)
Hints everything was working fine with nodejs 14
that's how my package.json lunch scipt look like
"main": "src/index.js",
"type": "module",
"scripts": {
"dev": "nodemon --es-module-specifier-resolution=node src/index.js",
},
I get no error when starting the server
The Issue was with Insomnia ,
when I tried curl it worked

How to connect Express backend and Next.js frontend?

I modified my server.js(by looking at Vercel site)
connectDB();
const routes = require('./routes');
const blogpost = require('./routes/blogpost');
const auth = require('./routes/auth');
const users = require('./routes/users');
const comments = require('./routes/comments');
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handler = routes.getRequestHandler(app);
app.prepare()
.then(() => {
const server = express();
server.use(handler);
server.use(express.json());
server.use(cookieParser());
server.use(mongoSanitize());
server.use(helmet());
server.use(xss());
if (process.env.NODE_ENV === 'development') {
server.use(morgan('dev'));
}
const limiter = rateLimit({
windowMs: 10 * 60 * 1000,
max: 100,
});
server.use(limiter);
server.use(hpp());
server.use(cors());
server.use('/api/v1/auth', auth);
server.use('/api/v1/blogpost', blogpost);
server.use('/api/v1/users', users);
server.use('/api/v1/comments', comments);
const PORT = process.env.PORT || 5000;
server.listen(PORT, console.log(`Server running in ${process.env.NODE_ENV} mode on port ${PORT}`));
});
Backend and frontend are separate folders,so I figured out that concurrently help me solve this.
My package.json
"scripts": {
"start": "node server",
"client": "cd ..//frontend && npm run dev",
"server": "nodemon server",
"dev": "concurrently --kill-others-on-fail \"npm run client\" \"npm run server\"",
"test": "jest"
},
I got error
internal/modules/cjs/loader.js:1083
[1] throw err;
[1] ^
[1]
[1] Error: Cannot find module 'react'
[1] Require stack:
[1] - /home/jholmes/blog_mongo/backend/node_modules/next/dist/next-server/server/render.js
[1] - /home/jholmes/blog_mongo/backend/node_modules/next/dist/next-server/server/nextserver.js
[nodemon] app crashed - waiting for file changes before starting...
[0] ready - started server on http://localhost:3000
[0] event - compiled successfully
I can signup at the frontend but no data is passed to the backend.
What is wrong with my configuration?
From your explanation and package.json file, it seems you were creating a microservices application where the backend standalone from the frontend.
But your server.js file shows that you were creating a monolithic application where the frontend and backend is on the same instance.
The error message explains that to do Server Side Rendering (SSR), it needs reactjs library to render the frontend, unfortunately couldn't find reactjs because your backend supposed to not having reactjs.
If you want to create microservices application, then the way frontend connect to backend is via APIs. If you tend to have monolithic application, then you need to read the SSR documentation of NextJS.

How to properly configure Next.js as a frontend and Express app as a backend?

Currently I have create-react-app for frontend and express server for backend. In package.json of my create-react-app I use proxy like this "proxy": "http://localhost:5000".
I need to achive the same thing for Next.js app with the same express server.
I just want to be able to use my express server instead of API routes built in Next.js and proxy it like I do in create-react-app.
Do I need to create custom Next.js server even though i'm not changing any of it's functionality? How to do this properly?
yes you have to add custom server in next js
install express js then add file server.js in root directory of next js project
const express = require('express')
const next = require('next')
const bodyParser = require('body-parser')
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare().then(() => {
const server = express()
server.use(bodyParser.json())
// add custom path here
// server.post('/request/custom', custom);
server.get('*', (req, res) => {
return handle(req, res)
})
server.listen(3000, (err) => {
if (err) throw err
console.log('Ready on http://localhost:5000')
})
})
after that change package.json file script section
"scripts": {
"dev": "node server.js",
"build": "next build",
"start": "NODE_ENV=production node server.js",
}

json-server does not use the code provided in the middleware file

I am using json-server to simulate some api calls responses for front-end development turns out that adding a middleware does not really work out in my case:
{
"name": "my-app",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "concurrently -k \"json-server --watch api-faked/db.json --routes api-faked/routes.json --middlewares api-faked/middleware.js --ro\" \"vue-cli-service serve\"",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
When starting:
[1] INFO Starting development server...
[0]
[0] \{^_^}/ hi!
[0]
[0] Loading api-faked/db.json
[0] Loading api-faked/routes.json
[0] Loading api-faked/middleware.js
[0] Done
[0]
It seems that the middleware.js is considered by json-server, however, a simple example such as the middleware.js like below:
module.exports = (req, res, next) => {
res.header('X-Hello', 'World')
next()
}
Does not add any header to my response headers:
Request URL: http://localhost:3000/api/v1/operations/?code_like=adi
Request Method: OPTIONS
Status Code: 204 No Content
Remote Address: 127.0.0.1:3000
Referrer Policy: no-referrer-when-downgrade
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: authorization
Access-Control-Allow-Methods: GET,HEAD,PUT,PATCH,POST,DELETE
Access-Control-Allow-Origin: http://localhost:8080
Connection: keep-alive
Content-Length: 0
Date: Thu, 18 Jul 2019 12:23:53 GMT
Vary: Origin, Access-Control-Request-Headers
X-Powered-By: Express
What am I missing here?
Side-note: actually removing the next from the middleware.js does not even alter anything, it's like even though the middlware has been added to the json-server configuration it seems not really run at any point in time.
The solution in my case was using the module style of json-server, which basically involves creating a js file and recreating router which is otherwise created automatically with the db.json and routes.json, unlike the automatic mode, it supports adding a middleware which can intercept pretty much everything.
Example
const fs = require('fs');
const jsonServer = require('json-server');
const path = require('path');
const server = jsonServer.create();
const defaultMiddleware = jsonServer.defaults();
// It is recommended to use the bodyParser middleware before any other middleware in your application
server.use(jsonServer.bodyParser);
server.use(defaultMiddleware);
// Define custom routes (routes.json)
const routes = JSON.parse(fs.readFileSync(path.join(__dirname, 'routes.json')));
server.use(jsonServer.rewriter(routes));
// Add custom middleware before JSON Server router
const customMiddleware = require(path.join(__dirname, 'middleware.js'));
server.use(customMiddleware);
// This is where `json-server`'s magic happens ;)
const router = jsonServer.router(path.join(__dirname, 'db.json'));
// Start the application by listening to port 3000,
// Although this won't print the nice starting message you see when
// running `json-server` as CLI command, it still runs the app correctly.
server.use(router);
server.listen(3000, () => {
console.log('JSON Server is running')
});
With the structure of the folder api-faked being:
server.js
middleware.js
db.json
routes.json
Instead of serving the application like that (in package.json):
"serve": "concurrently -k \"json-server --watch api-faked/db.json --routes api-faked/routes.json --middlewares api-faked/middleware.js --ro\" \"vue-cli-service serve\"",
it is now like this:
"serve": "concurrently -k \"nodemon api-faked/server.js --watch api-faked/*.*\"
I also use nodemon which restart the json-server if any change occurs in any of the given files (ie. --watch api-faked/*.*)
I've been put on the right track thanks to the answer given in that GitHub issue: json-server does not use the code provided in the middleware file
You may be missing the actual call to tie/link the middleware to your express app. Try calling:
app.use(enter_middleware_function_here);
This is assuming you instantiated your app similar to:
const express = require('express')
const app = express()

Heroku - React application is calling localhost in fetch() requests instead of the Heroku URL for my Express backend

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

Resources