Cannot execute HTTP GET call twice on nodejs/express backend - javascript

Using the packages express and ````ftp``` I try to simply get files from an ftp and return
them by HTTP GET to the client requesting.
The first request goes through fine, but when I try calling it again I run into Exception:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
I've tried to use the solutions from Error: Can't set headers after they are sent to the client like having a return when sending, not setting , unfortunately none of the worked for me.
This is ALL the code:
const express = require('express');
const ftp = require('ftp');
const app = express();
const port = 3000;
const c = new ftp();
app.get('/files', (req, res) => {
c.on('ready', () => {
c.list((err, list) => {
c.end();
return res.setHeader("Content-Type", "application/json").status(200).send({data: list});
});
});
c.connect({
host: 'xxx',
user: 'xxx',
password: 'xxx',
});
});
app.listen(port, () => {
console.log(`Example app listening on port ${port}`);
});
I think it might be something with the c.list() callback, however I cannot for the love of god find what is wrong with it, as the res.send() does not get called twice anytime.

The problem is you have just one ftp object, and every request subscribes to (and never unsubscribes from) the ready event, and the ready event fires every time you call connect() , which you do for every request. So when the second request calls connect(), the event fires for both the first and second request. This leads to setHeader() being called a second time for the first request, hence the error.
Using once() instead of on() so that the event handler it only called once should resolve the issue, though there are probably better ways to write this code (use a promise API or promisify this one, only initialize a connection to the FTP server once instead of for every request).

Related

Get 404 error When trying to fetch data from Node.js in React.js While server is running

I am not familiar with back-end and it is the first time to try it out.
Techset is React.js, Node.js, express.js, and mysql.
I want to request result of a query but 404 error occurs.
This is the code.
In React.js
const resident_name = 'sss';
let rates = [];
async function getData(){
const res = await fetch('http://localhost:3001', {
method: 'POST',
mode: 'cors',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({name: {resident_name}}),
});
rates = await res.result;
};
getData();
I want to execute the function as soon as the page that has it shows up.
In Node.js
app.post("/", (req,res)=>{
res.set('Content-Type', 'application/json');
console.log("i got "+req.body.name);
db.query(`SELECT r.*
FROM rate r INNER JOIN resident rs on r.resident_id = rs.resident_id
WHERE rs.name = ${req.body.name}`, (err,result)=>{
// result is an array that contains dictionaries.
if(err) throw err;
result.forEach(r => {
console.log(r)
});
res.send(result)
});
});
I am not sure what causes the error. Can I plz get solution if you guys know some info about it?
Thank you!
Edited: I am running both React.js on port 3000 and Node.js on port 3001. Once I type node index.js, I can see Server is listening to 3001 message on server-side console with this code below.
app.listen(PORT, () => {
console.log(`Server listening on ${PORT}`);
});
Result on the console:
Server listening on 3001
I'm working on making sure the server is running in the way the first answer suggested.
first, make sure your server's API endpoint is correct and running.
For that, you can use Vs code extension like Thunder client by
passing your port.
And check for any network issue using ping command or firewall
block.
Also, check your header request or use tool like curl. In
react.js while request from server, CORS also block to make request
on the browser (as i have face same issue on past). So, make sure you
check the server logs.
404 error occurs only if there is nothing is listening in the mentioned address:port.
Make sure you are requesting to the correct url with correct port number in which your express app is running.
Express app defaults to port 3000

i can't figure out why we are using response.on

I've written a code here and I want to know what "response.on" is doing and why we are passing "data", what is this "data".
what exactly that ".on" is used for.
const express = require("express");
const https = require("https");
const app = express();
app.get("/",function(req,res){
const url="https://api.openweathermap.org/data/2.5/weather?q=London&appid=5c8618a9210a11846accc217f3b3084f";
https.get(url,function(respons){
response.on("data",function(data){
const wht = JSON.parse(data)
temp = wht.main.temp
res.send("temp "+ temp)
})
})
})
app.listen(3000, function(){
console.log("running");
});
.on("nameOfEvent", callback) it's a event emitter. So, basically whenever that event is called, that callback will be executed. data is just the name of the event.
In your code there is bug.
You using respons in the argument of function and response inside of function.
Waiting on data of response is documented in https
https://nodejs.org/api/https.html#https_https_get_options_callback
You can read that response is not a classical response from the server but an event listener that listens for stream of data.
It is a low-level interface and in your applications, you should not use them. Lets interest in node-fetch or axios instead if you want only get a response, but not process streams in real-time.

How can I receive data using socket.io?

I am running a server using expressjs. Whenever a user accesses to one of my specific url (for this purpose, just imagine it will be https://server.com/test), I want to emit a data to another webserver using socketio, listen to the data and respond to the user with the data I have received.
Few things to note:
My server expects nothing but just an access to the https://server.com/test url.
Another server, which I want to connect using socket.io and obtain data expects me to send an argument of {"got" : "true"} to parameter called "test".
When another server receives the socket emit from my server on parameter "test" with arguments specified above, it simply replies back with an argument {"message" : "true"}
My code is quite simple and looks like this (router) :
const express = require("express");
const router = express.Router();
//const Goal = require("../models/battery_message");
const mongoose = require("mongoose");
const io = require("socket.io-client");
const host = "https://another_server.com"
const socket = io(host, {query:"email=edmund#gmail.com"});
console.log("connected");
router.get('/', function(req,res) {
socket.emit("test_me", {"got" : "true"}, function(data){
exists = data;
console.log(data);
});
});
module.exports = router;
The problem I have is whenever the user accesses my server on https://server.com/test nothing happens, as no response comes like in an infinite loop. My guess is that I need some kind of another socket.emit because another server probably emits its response to the socket too, but I might be wrong.
So to sum up, my question is, what do I need to add in order to successfully get the response from another server?

Access grpc stream variable for long-running process in Node

I am using Node.js to connect to a server using gRPC that performs a long running task.
The server sends a unidirectional stream to the client (the Node.js app) while the job is in progress. I need to implement a Stop button and am told that closing the gRPC stream will stop the job in progress.
This is currently my code:
let express = require('express'),
router = express.Router(),
grpc = require('grpc'),
srv = grpc.load(__dirname + '/job_handler.proto').ns;
let startJob = (jobID, parameters) => srv.createJob(jobID, parameters);
router.post('/jobs', (req, res) => {
let lengthyOperation = startJob(jobID, parameters);
lengthyOperation.on('data', (data) => {
console.log(`Data from lengthy operation: ${data}`);
});
lengthyOperation.on('end', () =>
console.log('Lengthy operation completed');
});
res.setHeader('Location', `/jobs/${jobID}`);
res.status(202).send();
});
As you can see, I send an HTTP 202 response to the client upon creating the job and it continues asynchronously in the background.
Questions:
How do I close the stream?
How do I access the lengthyOperation variable to do so?
The lengthyOperation object has a cancel method that cancels the call. So, when you want to stop the stream, just call lengthyOperation.cancel().
Note that when you do this, it will cause the call to end with an error. I would recommend adding a lengthyOperation.on('error', ...) handler to handle that error.

How to know when node.js express server is up and ready to use

Have an application where I want to start a node express server and then start a browser on the same machine automatically as soon as the server is up. How can I query to see if the server is up and ready to go? I really wanted there to be some sort of callback on the .listen call, but doesn't seem to be. I could just wait a longer than I expect amount of time, but this is going on equipment that will be in the field so I either have to wait a ridiculous amount of time to make sure I'm up and running before kicking off the browser or have the user be smart enough to hit refresh if the page doesn't load right. Neither of those are good options for me. . .
I read the API online but don't see anything like this. Surely there's a trick I don't know that can accomplish this.
If the node HTTP api (which has a callback and tells me about the listening event) is the base for the express object, maybe there is a callback option for the express call listen that isn't documented. Or perhaps I'm supposed to just know that it's there.
Any help would be greatly appreciated.
The Express app.listen function does support a callback. It maps the arguments that you pass in to the http.listen call.
app.listen = function(){
var server = http.createServer(this);
return server.listen.apply(server, arguments);
};
So you can just call: app.listen(port, callback);
Or you could use http.listen directly.
var app = require('express')(),
server = require('http').createServer(app);
server.listen(80, function() {
console.log('ready to go!');
});
You can fire a custom event after the server is started:
// server.js
const express = require('express');
const app = express();
modeule.export = app;
app.listen(3000, () => {
app.emit('listened', null)
});
In a separate module, the app can listen your custom event:
// custom.js
const server = require('server.js');
server.on('listened', function() {
console.log('The server is running!');
});
You can use the http.listen method which has a callback function that triggers once the server is ready:
http.createServer(app).listen(app.get('port'), function () {
console.log('Printed when ready!!!');
});
See the official reference at Node.js:
http://nodejs.org/api/all.html#all_server_listen_port_hostname_backlog_callback
http://nodejs.org/api/all.html#all_server_listen_path_callback_1
http://nodejs.org/api/all.html#all_server_listen_handle_callback_1
As many have mentioned, the listen function (on the express app or an http server, both support it), does support a callback and that will let your node process know when it is listening.
So if you plan to launch the browser from within your express app, do it there and you are good. However, if you are launching the express app from an external script and then want that external script to open the browser, the node callback doesn't really buy you anything.
Waiting for some magic string on stdout isn't really an improvement on just waiting for a good HTTP response. You may as well just use a try/backoff/timeout loop with curl until you get a successful response.
server.on('listening', function() {
resolve();//I added my own promise to help me await
});
The Listening event worked for me. Note I added my own Promise. I imagine you could obtain similar results without a promise by adding an entry point to this listener.
Note, I tried the more intuitive server.on('listen') and it didn't work. Running node 6.9.1
With async/await syntax, this can be done by wrapping the server startup in a promise, so you can wait for it to be started before running anything else:
import express from 'express';
import http from 'http';
const app = express();
let server: http.Server;
const startServer = async (): Promise<void> => {
return new Promise((resolve, _reject) => {
server = app.listen(3000, () => {
console.log('Express server started');
resolve();
});
});
};
await startServer();
// here the server is started and ready to accept requests

Categories