I have been working on a NodeJS express app that uses EJS and node-fetch to fetch my Api from my vps server, but it won't get fetched, every page of the app will load but the page that uses the Api where I am fetching the Api won't work, I have been trying to solve this issue for almost a week now but cannot get anywhere
My App.js
const express = require('express');
//node fetch used here is a fork of the original and i have tried both original and this
//both have the same result
const fetch = require('#formio/node-fetch-http-proxy');
const port = 3000;
...
...
... <- some code here
...
...
app.get('/', (req, res) => {
res.render('index');
});
app.get('/xyz',(req,res) => {
var url = 'http://XX.XX.XX.XX:8080/api';
try {
fetch(url, {
method: 'GET',
headers: {
'api-key': process.env.API_KEY,
'Content-Type': 'application/json'
}
}).then((resp) => {
return resp.json();
}).then((data) => {
...
... <- some code here
...
res.render('xyz',{categories: categories , ...});
}).catch((err) => {
console.log(err);
});
}
catch(err) {
console.log(err);
}
});
...
... <- some code here
...
Error I am getting :-
With both Axios and node-fetch I have been getting a common error of
connect ECONNREFUSED XX.XX.XX.XX:8080
Some of the things that I have tried :-
I have switched from Axios to node fetch thought maybe that had to do something with it, I have hosted a new node app on vps that when requested will show a msg in console that a request was made and pass the Json by locally fetching it, when I made a request from postman it worked the console logged 'Request was made' but when I tried it on the cPanel hosted app it did not show anything, I have also tried making my Api a https response but that did not work ether.
Note :-
The app is working fine when i host it in local pc, when i host the node app in cPanel it won't work.
Solution Found :-
because I am new to web developing and never used cPanel before, I had to allow my backend vps server Ip after contacting my web server provider he allowed the Ip and now it's working like a charm
Related
Everything runs smoothly locally, and I can make HTTP requests to other routes just fine. However the one route that makes requests to the Twitch API is giving me no response. I believe this has something to do with the port, or the redirect URI.
If I run my local version it will work on the Heroku deployment, so I think that means there's an issue with my redirect URI or port. I've tried removing the || 5000 option in express, changing my redirect URL on twitch, but I can't quite get anything to work. The app is pretty small, it just searches channels through the Twitch API.
Twitch Api Redirect URL:
https://twitchfinder.herokuapp.com/
Heroku Config Vars:
CLIENT_ID.
CLIENT_SECRET
REDIRECT_URI. appname.herokuapp.com
REDISCLOUD_URL
Express Port:
const port = process.env.PORT || 5000;
app.listen(port, () => {
console.log(`App is running on port ${port}`);
});
Express Route (again, works fine locally, or if I just have this route send something other than the twitch API)
app.get("/search/:channels", async (req, res) => {
const { channels } = req.params;
const results = await twitchSearch(channels, CLIENT_ID);
res.json(results);
});
GET request function:
async function twitchSearch(query, CLIENT_ID) {
const access_token = await client.get("access_token");
console.log(access_token);
const response = await axios
.get(`https://api.twitch.tv/helix/search/channels?query=${query}`, {
headers: {
Authorization: `Bearer ${access_token}`,
"Client-Id": CLIENT_ID,
},
})
.then((res) => {
data = res.data.data;
return data;
})
.catch((e) => {
console.log("error from inside twitchSearch", e);
});
return response;
}
I'm also running middleware, with Cors, serving a static 'build', and running a validation middleware that's set to a cron job.
I can post my get token or validate functions as well, but I think I've narrowed down the issue to the redirect url/uri or a port issue... I'm just at a loss to the solution after a few days.
I am at early stages setting up a next.js application, I only had experience using react so far.
I setup docker with a frontend app (next.js) on localhost:3000 and a backend app (node.js/express) on localhost:5000. They both work.
Now I am trying to call an express endpoint from the frontend, what I am doing is:
const registerUser = async event => {
event.preventDefault()
const res = await fetch(
process.env.NEXT_PUBLIC_SERVER + '/user/signup',
{
body: JSON.stringify({
username: event.target.name.value,
email: event.target.email.value,
password: event.target.password.value
}),
headers: {
'Content-Type': 'application/json'
},
method: 'POST'
}
)
result = await res.json()
}
and I am getting an error saying
Access to fetch at 'http://localhost:5000/user/signup' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
just a note: the endpoint works as expected using Postman.
I made some research and I find a few resources saying I should call an internal next.js endpoint (pages/api), and from there call my api. Is this the best practice with next.js? In react I just use to call the api directly.
Other than just how to solve this, I would like to know what's the best practice in this case? Thanks.
If you have separate servers for frontend and backend (for example, next.js and express) that cannot listen on the same port, there are two broad alternatives:
Either the browser loads the frontend from one server and makes API requests to the other server
next.js <-- browser --> express
This requires the backend app to set CORS headers, for example, using cors and the statement
app.use(cors({origin: "host of next.js", ...}));
Or the browser makes all requests to the port of next.js, and this forwards all API requests to the other server
browser --> next.js --> express
No CORS is necessary in this case, but API requests take more hops than before. So it is simplicity vs performance (like so often).
First of all, are you sure you need an Express BE? The power of Next.js relies in its serverless approach, most of times, unless you have a very complex BE, you can do everything with serverless functions.
If you really need to have a separate express server for your Next application remember that you will lose some important Next features:
Before deciding to use a custom server, please keep in mind that it should only be used when the integrated router of Next.js can't meet your app requirements. A custom server will remove important performance optimizations, like serverless functions and Automatic Static Optimization.
Usually to address the CORS issues in dev environment, since you need FE to run on a different PORT from BE to have Hot Reload, when you use React the best approach is the proxy approach, you can just add an entry to package.json on the React project,
"proxy": "http://localhost:5000" (if your server runs on PORT 5000)
Source: https://create-react-app.dev/docs/proxying-api-requests-in-development/
This way all the http traffic is going to be redirected on port 5000 and will reach your Express server, while keeping having hot reload features and your client files running on port 3000.
By the way, that's the case if you have a standard React FE and a custom Express BE, if you are using NextJS even with a custom Express Server, you need to create the server and to connect it using Next:
/ server.js
const { createServer } = require('http')
const { parse } = require('url')
const next = require('next')
const dev = process.env.NODE_ENV !== 'production'
const hostname = 'localhost'
const port = 3000
// when using middleware `hostname` and `port` must be provided below
const app = next({ dev, hostname, port })
const handle = app.getRequestHandler()
app.prepare().then(() => {
createServer(async (req, res) => {
try {
// Be sure to pass `true` as the second argument to `url.parse`.
// This tells it to parse the query portion of the URL.
const parsedUrl = parse(req.url, true)
const { pathname, query } = parsedUrl
if (pathname === '/a') {
await app.render(req, res, '/a', query)
} else if (pathname === '/b') {
await app.render(req, res, '/b', query)
} else {
await handle(req, res, parsedUrl)
}
} catch (err) {
console.error('Error occurred handling', req.url, err)
res.statusCode = 500
res.end('internal server error')
}
}).listen(port, (err) => {
if (err) throw err
console.log(`> Ready on http://${hostname}:${port}`)
})
})
source: https://nextjs.org/docs/advanced-features/custom-server
Again, I suggest you to deeply evaluate if you really need a custom express server for your app, because most of times you don't, and development experience is much smoother in a serverless environment!
I'm finally dipping my toe into the world of server side react using Next.js, however I'm pretty stumped with this issue.
I'm making a call to an API from pages/customer-preferences.tsx using isomorphic-unfetch
CustomerPreferencesPage.getInitialProps = async () => {
const res = await fetch(API_URL + '/preference-customer');
const initialData = await res.json();
return { initialData };
};
All works fine locally in dev mode or once built and ran build > start. To host it I'm running it from a docker container node:10, and when I run this locally all is fine also. The issue only happens once it's deployed.
When I navigate to / and then click a link to /customer-preferences all works as expected. But if I refresh the page or load the page directly at /customer-preferences I see this error from Next.js
So the issue only seems to happen when trying to make the API calls from the server and not the client.
I've also setup a simple express server to use instead, but not sure if this is necessary?!
const express = require('express');
const next = require('next');
const port = parseInt(process.env.PORT, 10) || 3000;
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
app.prepare().then(() => {
const server = express();
server.all('*', (req, res) => {
return handle(req, res);
});
server.listen(port, err => {
if (err) throw err;
console.log(`> Ready on http://localhost:${port}`);
});
});
When checking the server logs I get this:
FetchError: request to http://xxx failed, reason: getaddrinfo EAI_AGAIN xxx xxx:80
Any help would be greatly appreciated.
No, the server setup is not necessary.
This is happening because the browser/client is not capable of resolving your docker container's hostname. As it stands, the only solution I know of is to check for the req object in getInitialProps (so as to determine which environment the fetch will run in) and call the Docker hostname when on server, localhost when on client. E.g.
async getInitialProps (ctx) {
if (ctx.req) // ctx.req exists server-side only
{
// call docker-host:port
}
else {
// call localhost:port
}
}
My suspicion has to do with the fact that fetch is not a native node module but a client in browsers. So, if you navigate from one page to this page; per the documentation; getInitialProps will be called from the client side, making the fetch method accessible. A refresh ensures that the getInitialProps called from the server side.
You can test this theory by running typeof fetch from a browser's inspector and from a node REPL.
You are better of calling the method from component or using a third-party HTTP client like axios...
If you want to skip calling the AJAX method from the backend and only call it from the frontend, you can test if the method is calling from the frontend or the backend, like so:
CustomerPreferencesPage.getInitialProps = async () => {
if (typeof window === 'undefined') {
// this is being called from the backend, no need to show anything
return { initialData: null };
}
const res = await fetch(API_URL + '/preference-customer');
const initialData = await res.json();
return { initialData };
};
So I'm running it on port 8080. Port forwarding has been set up and it is working.
Every time I type in my no-ip domain, I get the response on the screen but when I'm making a request from my website, it logs the request on the Raspberry, yet, there is no response visible in the Chrome developer tools.
I also get this error message: POST "name of the api" net::ERR_EMPTY_RESPONSE
What could cause that? My routes worked perfectly when I was running my api locally.
module.exports = function(app) {
app.get('/', requireAuth, function(req, res) {
res.send({ message: 'OMG, You made it, you deserve a drink!' });
});
That's how my react app looks like:
const ROOT_URL = *"name of the api"/*;
.
.
.
export function fetchMessage() {
return function(dispatch) {
axios.get(ROOT_URL, {
headers: { authorization: localStorage.getItem('token') }
})
.then(response => {
dispatch({
type: FETCH_MESSAGE,
payload: response.data.message
});
});
}
};
Is it a typical problem of the Node.js, Express, React or maybe it's on the Raspi? Thanks a lot!
Possibly a CORS issue, since the problem only happens when trying to consume the API from the browser. A possible solution is to use the cors package in your Express application:
const express = require('express');
const cors = require('cors');
...
const app = express();
app.use(cors());
...
NOTE: this enables all CORS requests.
Im trying to send a POST request from my React application. The application is running locally in node on localhost:8000.
I've tried running in locally on localhost:5000 and also pushed the server application to a heroku webaddress and tried sending to that address.
So basically my question is;
1. how do I send a POST request to my heroku server when i'm running my react application locally on localhost?
2. How do I receive this POST request on my heroku server/node application?
React code for sending POST request:
import React, { Component } from 'react'
import axios from 'axios'
require('styles/_webshopPage/webshop.css')
export default class Checkout extends Component {
postRequest() {
let nodeServerURL = 'https://peaceful-mountain-93404.herokuapp.com'
let reqData = {
msg: 'hello!',
}
// Send a POST request
axios({
method: 'post',
url: nodeServerURL,
data: reqData
})
}
render() {
return (
<div >
<button onClick={this.postRequest.bind(this)} type="button" name="button">Send req</button>
</div>
)
}
}
Code for my heroku server:
var express = require('express')
var app = express()
app.set('port', (process.env.PORT || 5000))
app.use(express.static(__dirname + '/public'))
app.post('/', function(request, response) {
response.send('Hello World!')
})
app.listen(app.get('port'), function() {
console.log("Node app is running at localhost:" + app.get('port'))
})
I have done something similiar like that..
I think Fetch api works perfectly with it .
Fetch provides a generic definition of Request and Response objects (and other things involved with network requests). This will allow them to be used wherever they are needed in the future, whether it’s for service workers, Cache API and other similar things that handle or modify requests and responses, or any kind of use case that might require you to generate your own responses programmatically.
I have typing some random example here, hope it will you to understand how fetch api exactly works
var data= "somerandom string";
fetch('http://localhost/react_task/form_send.php', {
method: 'post',
body: JSON.stringify({
Password: data,// this is posted on another server
})
}).then(function (res) {
return res.text();
}).then((body)=> {
console.log(body)// body can be used to get data from another server
});
i think fetch helps perfectly lot for posting and getting data from another server..
Enjoy Coding.