Fetch gives empty response while waiting for long period - node.js

I have app made with react and node .
The react app needs to make api call to the node app the node app is running on port 5100 . I am facing problem where I get net_err empty response in the console after waiting long period of time . The thing is my api takes 200s to get the response from the server .
When I hit
http://localhost:5100/api/users/wait-ip
I get response after 200 second But when I hit this in the react app
fetch('/api/users/wait-ip')
I get the following error on console
GET http://localhost:3000/api/users/wait-ip net::ERR_EMPTY_RESPONSE
This is my function for api
router.get('/api/users/wait-ip',(req,res)=>{
//Others things happen here
setTimeout(()=>{
return res.json({
data:1
})
},150000)
})
This is the response I get while hitting directly on browser after 150seconds
Any help on how to solve this will be appreciated

Using Node.js API with React is a common use case. I think the reason you are facing the issue in getting response is that you are using fetch call synchronously. Always use async/await for it.
async function getUsers() {
let response = await fetch('/api/users/wait-ip');
let users= await response.json();
//...
return users;
}
Using the function:
getUsers().then(result => {console.log(JSON.stringify(result));});
Hope that helps.

For me the problem was on both client and the server .
I have read some of the post on how to fix timeout on the server . One of them was
const server = http.listen(port, () => console.log(`Server running on port ${port}`));
server.timeout = 200000;
Well this worked but only for the direct browser call .
For the asynchronous call I need to set it for each function where I wanted it like this
router.get('/wait-ip',(req,res)=>{
req.timeout =160000;
setTimeout(()=>{
return res.json({
data:1
})
},150000)
})
And for client part with pxoy it didn't work properly . So what I did was posted the full url
fetch('http://localhost:5100/api/users/wait-ip')
I hope this helps with other person too

I may be because of the Cross Origin Resource Sharing (CORS) header. Usually calling from a browser there is an "OPTION" call that is made followed by, in this case, the "GET".
I would try
fetch('/api/users/wait-ip', {
mode: 'no-cors' // 'cors' by default
})
If this fixes the problem either you force not to use cors on the client side. Or the server should manage it. Another option is to allow the proxy to set these headers.
ref: https://developers.google.com/web/ilt/pwa/working-with-the-fetch-api
section: Cross-origin requests

This is an API problem. I'd make set breakpoints in your API and make sure the right fields are populated for the response.
Node.js Debugging Guide...

Related

How can I log the express endpoint hit if the server crashes during an asynchronous callback?

I have an express service where a lot of my endpoints look like the following.
var express = require('express');
var router = express.Router();
router.get('/updateThisValue', (req, res) => {
let value = req['query'].value
try {
database.update(value, function() { // callback function on update
console.log(undefinedValue.undefined) // crash the server
})
} catch (err) {
// Log the error and other stuff
}
})
Looking at this code, if a database update is called, something will crash in the callback function and since there is no try-catch, the whole server should crash as well.
Right now, I am okay with the server crashing. The problem is that I would like to be able to log some debugging information in the callback before it crashes, namely the express endpoint hit and the parameters passed to it.
One solution is that I could just log every single endpoint hit, but the only problem with that is that the server starts to have very large logs. So we don't log endpoints hit by default. The frustration however is that recently an endpoint hit the server that did cause it crash and I'm still unsure what the actual endpoint hit and parameters passed to it where.
Basically, I want the server to still crash but at least I would be able to trace the endpoint hit and its parameters
Could this help: https://expressjs.com/en/guide/error-handling.html
Normally you would see the exception in the console or in the logs of your process manager (like pm2).

Send request progress to client side via nodejs and express

I am using this (contentful-export) library in my express app like so
const app = require('express');
...
app.get('/export', (req, rex, next) => {
const contentfulExport = require('contentful-export');
const options = {
...
}
contentfulExport(options).then((result) => {
res.send(result);
});
})
now this does work, but the method takes a bit of time and sends status / progress messages to the node console, but I would like to keep the user updated also.. is there a way I can send the node console progress messages to the client??
This is my first time using node / express any help would be appreciated, I'm not sure if this already has an answer since im not entirely sure what to call it?
Looking of the documentation for contentful-export I don't think this is possible. The way this usually works in Node is that you have an object (contentfulExport in this case), you call a method on this object and the same object is also an EventEmitter. This way you'd get a hook to react to fired events.
// pseudo code
someLibrary.on('someEvent', (event) => { /* do something */ })
someLibrary.doLongRunningTask()
.then(/* ... */)
This is not documented for contentful-export so I assume that there is no way to hook into the log messages that are sent to the console.
Your question has another tricky angle though. In the code you shared you include a single endpoint (/export). If you would like to display updates or show some progress you'd probably need a second endpoint giving information about the progress of your long running task (which you can not access with contentful-export though).
The way this is usually handled is that you kick of a long running task via a certain HTTP endpoint and then use another endpoint that serves infos via polling or or a web socket connection.
Sorry that I can't give a proper solution but due to the limitation of contentful-export I don't think there is a clean/easy way to show progress of the exported data.
Hope that helps. :)

Express request fires a second time

I'm at a little standstill here.
I'm creating an express app that have to export a huge amount of data from a Shopify store with a single request.
The issue is that when I reach the 2min mark the request is fired again ( since the default timeout is 2min ), so I increased the server.setTimeout() to take in consideration the time that it needs.
So this fixed the fire of the request on the 2min mark, but once my request finish, once again for some reason a second request is made.
Here is a bare bone example of the issue:
const express = require('express');
function sleep(ms){
return new Promise(resolve=>{
setTimeout(resolve,ms)
})
}
app.get('/export', async (req, res) => {
// Sleep for 2:03min
await sleep(123000);
console.log('Starting request');
res.status(200).send('Finish');
})
const server = app.listen(3000, () => {
console.log(`Example app listening on port ${port}`)
})
// Set timeout to 2:04min
server.setTimeout(124000);
If you open http://localhost:3000/export the result form the above code returns:
Starting request <- at the beginning
Starting request <- at the 2:04 mark
Is this some issue because of the async/await, since it seems that res.send() never fires ?
Can someone clarify "why" is this happening and "how" to prevent it?
PS: I can't use a flag or something to check if the request was already made, since the APP needs to work for users exporting the data at the same time, and the second request comes as a brand new one.
Well I lost around 4 hours on this today and the conclusion is that my tunel service ( http://serveo.net/ ) was firing another request at some point perfectly timed when my export is done. ( as for why, I don't have an answer to that ) I'm still not sure if this is the correct conclusion, but switching to a different option ( or using the direct localhost ) didn't show any issues.
I moved to OpenVPN and all of my problems were gone. Ngrok was OK as well, but since the free version didn't have a fixed URL ( and it's a pain to change all of the end points in the App setup each day I start the service ) I went with OpenVPN.
The root of the problem was that res.status(200).send('Finish') was never firing for some specific reason or if it was it sure didn't seems so.
Thanks for all of the help.

Can't set headers after they are sent error happens with socket.io

I am writing a very simple nodejs socket.io app. Somehow this returns "can't set headers after they are sent" error. but I can't see the point where the header is set again. I've only called server.listen once and I believe socket.listen works independently so it shouldn't conflict.
I am aware that can't set headers error had been posted a multiple times. I've read them briefly and I also understand how does response.writeHead works under normal circumstances(I've experimented with some node.js apps with response.writeHead, they worked fine most cases) it seems I am missing something from here. is it due to socket.io?
const fs = require("fs");
const server = require("http").createServer();
const io = require("socket.io").listen(server);
server.listen(52273,function(){
console.log("server up");
});
server.on("request",function(request,response){
fs.readFile("mainpage.html",function(error,data){
response.writeHead(200,{"Content-Type":"text/html"});
response.end(data);
});
});
io.sockets.on("connection",function(socket){
var roomName = null;
socket.on("join", function(data){
roomName = data;
socket.join(data);
console.log("client joined" + data);
});
socket.on("message",function(data){
io.sockets.in(roomName).emit("message","test");
});
});
It probably helps a bit here to understand a little bit about how socket.io works with your web server. socket.io uses the webSocket protocol as it's base protocol. A webSocket connection starts with an HTTP request that has special header set in it to indicate the start of a webSocket connection. A properly functioning web server will see this webSocket header and turn the request over to the webSocket handler to initiate the webSocket connection.
But, this handler you have:
server.on("request",function(request,response){
fs.readFile("mainpage.html",function(error,data){
response.writeHead(200,{"Content-Type":"text/html"});
response.end(data);
});
});
Looks like it is responding to every single request that arrives and sending a response, no matter what the request was. So, I can imagine that when the webSocket request comes in you're sending two responses, one from the webSocket server code and one from your request handler above.
Probably, you need to be able to only send your mainpage.html response for particular URLs that are not your webSocket request.
To see a little more about what's going in, insert a console.log() into here:
server.on("request",function(request,response){
console.log(request.url);
fs.readFile("mainpage.html",function(error,data){
response.writeHead(200,{"Content-Type":"text/html"});
response.end(data);
});
});
And, you will probably see you are sending your mainpage.html to a webSocket request which is not what you want to do. You will likely want to add some if logic so that your request handler is avoiding the webSocket requests.
What version of Node you using?
We had the same problem when we were using 0.9.x. I downgraded Node to 0.8.4 and the problem seems to have gone away.
My best guess is something in Node has changed that Socket.io doesnt agree with.
Thanks everyone. I've solved problem by installing express to my experiment app. I've read the manual again and discovered the socket.io v2 is now requiring express app as a dependency. It seems I have been using socket.io v2 but somehow sticked to socket.io v1 style app writing. It also worked when I downgraded it to socket.io v1.
TL;DR - socket.io v2 is not compatible with apps written for socket.io v1. When a socket.io app returns "can't set headers after they are sent" errors, try use proper version of the socket.io or install correct dependencies.

NodeJS - What does "socket hang up" actually mean?

I'm building a web scraper with Node and Cheerio, and for a certain website I'm getting the following error (it only happens on this one website, no others that I try to scrape.
It happens at a different location every time, so sometimes it's url x that throws the error, other times url x is fine and it's a different url entirely:
Error!: Error: socket hang up using [insert random URL, it's different every time]
Error: socket hang up
at createHangUpError (http.js:1445:15)
at Socket.socketOnEnd [as onend] (http.js:1541:23)
at Socket.g (events.js:175:14)
at Socket.EventEmitter.emit (events.js:117:20)
at _stream_readable.js:910:16
at process._tickCallback (node.js:415:13)
This is very tricky to debug, I don't really know where to start. To begin, what IS a socket hang up error? Is it a 404 error or similar? Or does it just mean that the server refused a connection?
I can't find an explanation of this anywhere!
EDIT: Here's a sample of code that is (sometimes) returning errors:
function scrapeNexts(url, oncomplete) {
request(url, function(err, resp, body) {
if (err) {
console.log("Uh-oh, ScrapeNexts Error!: " + err + " using " + url);
errors.nexts.push(url);
}
$ = cheerio.load(body);
// do stuff with the '$' cheerio content here
});
}
There is no direct call to close the connection, but I'm using Node Request which (as far as I can tell) uses http.get so this is not required, correct me if I'm wrong!
EDIT 2: Here's an actual, in-use bit of code that is causing errors. prodURL and other variables are mostly jquery selectors that are defined earlier. This uses the async library for Node.
function scrapeNexts(url, oncomplete) {
request(url, function (err, resp, body) {
if (err) {
console.log("Uh-oh, ScrapeNexts Error!: " + err + " using " + url);
errors.nexts.push(url);
}
async.series([
function (callback) {
$ = cheerio.load(body);
callback();
},
function (callback) {
$(prodURL).each(function () {
var theHref = $(this).attr('href');
urls.push(baseURL + theHref);
});
var next = $(next_select).first().attr('href');
oncomplete(next);
}
]);
});
}
There are two cases when socket hang up gets thrown:
When you are a client
When you, as a client, send a request to a remote server, and receive no timely response. Your socket is ended which throws this error. You should catch this error and decide how to handle it: whether retry the request, queue it for later, etc.
When you are a server/proxy
When you, as a server, perhaps a proxy server, receive a request from a client, then start acting upon it (or relay the request to the upstream server), and before you have prepared the response, the client decides to cancel/abort the request.
This stack trace shows what happens when a client cancels the request.
Trace: { [Error: socket hang up] code: 'ECONNRESET' }
at ClientRequest.proxyError (your_server_code_error_handler.js:137:15)
at ClientRequest.emit (events.js:117:20)
at Socket.socketCloseListener (http.js:1526:9)
at Socket.emit (events.js:95:17)
at TCP.close (net.js:465:12)
Line http.js:1526:9points to the same socketCloseListener mentioned by #Blender, particularly:
// This socket error fired before we started to
// receive a response. The error needs to
// fire on the request.
req.emit('error', createHangUpError());
...
function createHangUpError() {
var error = new Error('socket hang up');
error.code = 'ECONNRESET';
return error;
}
This is a typical case if the client is a user in the browser. The request to load some resource/page takes long, and users simply refresh the page. Such action causes the previous request to get aborted which on your server side throws this error.
Since this error is caused by the wish of a client, they don't expect to receive any error message. So, no need to consider this error as critical. Just ignore it. This is encouraged by the fact that on such error the res socket that your client listened to is, though still writable, destroyed.
console.log(res.socket.destroyed); //true
So, no point to send anything, except explicitly closing the response object:
res.end();
However, what you should do for sure if you are a proxy server which has already relayed the request to the upstream, is to abort your internal request to the upstream, indicating your lack of interest in the response, which in turn will tell the upstream server to, perhaps, stop an expensive operation.
Take a look at the source:
function socketCloseListener() {
var socket = this;
var parser = socket.parser;
var req = socket._httpMessage;
debug('HTTP socket close');
req.emit('close');
if (req.res && req.res.readable) {
// Socket closed before we emitted 'end' below.
req.res.emit('aborted');
var res = req.res;
res.on('end', function() {
res.emit('close');
});
res.push(null);
} else if (!req.res && !req._hadError) {
// This socket error fired before we started to
// receive a response. The error needs to
// fire on the request.
req.emit('error', createHangUpError());
req._hadError = true;
}
}
The message is emitted when the server never sends a response.
One case worth mentioning: when connecting from Node.js to Node.js using Express, I get "socket hang up" if I don't prefix the requested URL path with "/".
below is a simple example where I got the same error when I missed to add the commented code in below example. Uncommenting the code req.end() will resolve this issue.
var fs = require("fs");
var https = require("https");
var options = {
host: "en.wikipedia.org",
path: "/wiki/George_Washington",
port: 443,
method: "GET"
};
var req = https.request(options, function (res) {
console.log(res.statusCode);
});
// req.end();
I used require('http') to consume https service and it showed "socket hang up".
Then I changed require('http') to require('https') instead, and it is working.
Expanding on Blender's answer, this happens in a number of situations. The most common ones I run into are:
The server crashed.
The server refused your connection, most likely blocked by User-Agent.
socketCloseListener, as outlined in Blender's answer, is not the only place that hangup errors are created.
For example, found here:
function socketOnEnd() {
var socket = this;
var req = this._httpMessage;
var parser = this.parser;
if (!req.res) {
// If we don't have a response then we know that the socket
// ended prematurely and we need to emit an error on the request.
req.emit('error', createHangUpError());
req._hadError = true;
}
if (parser) {
parser.finish();
freeParser(parser, req);
}
socket.destroy();
}
You could try curl with the headers and such that are being sent out from Node and see if you get a response there. If you don't get a response with curl, but you do get a response in your browser, then your User-Agent header is most likely being blocked.
Another case worth mentioning (for Linux and OS X) is that if you use a library like https for performing the requests, or if you pass https://... as a URL of the locally served instance, you will be using port 443 which is a reserved private port and you might be ending up in Socket hang up or ECONNREFUSED errors.
Instead, use port 3000, f.e., and do an http request.
For request module users
Timeouts
There are two main types of timeouts: connection timeouts and read timeouts. A connect timeout occurs if the timeout is hit while your client is attempting to establish a connection to a remote machine (corresponding to the connect() call on the socket). A read timeout occurs any time the server is too slow to send back a part of the response.
Note that connection timeouts emit an ETIMEDOUT error, and read timeouts emit an ECONNRESET error.
This caused me issues, as I was doing everything listed here, but was still getting errors thrown. It turns out that calling req.abort() actually throws an error, with a code of ECONNRESET, so you actually have to catch that in your error handler.
req.on('error', function(err) {
if (err.code === "ECONNRESET") {
console.log("Timeout occurs");
return;
}
//handle normal errors
});
I had the same problem while using Nano library to connect to Couch DB. I tried to fine tune connection pooling with use of keepaliveagent library and it kept failing with socket hang up message.
var KeepAliveAgent = require('agentkeepalive');
var myagent = new KeepAliveAgent({
maxSockets: 10,
maxKeepAliveRequests: 0,
maxKeepAliveTime: 240000
});
nano = new Nano({
url : uri,
requestDefaults : {
agent : myagent
}
});
After some struggling I was able to nail the problem - as it came out it was very, very simple mistake. I was connecting to the database via HTTPS protocol, but I kept passing to my nano object a keepalive agent created as the examples for use of this library show (they rely on some defaults that use http).
One simple change to use HttpsAgent did the trick:
var KeepAliveAgent = require('agentkeepalive').HttpsAgent;
I think "socket hang up" is a fairly general error indicating that the connection has been terminated from the server end. In other words, the sockets being used to maintain the connection between the client and the server have been disconnected. (While I'm sure many of the points mentioned above are helpful to various people, I think this is the more general answer.)
In my case, I was sending a request with a payload in excess of 20K. This was rejected by the server. I verified this by removing text and retrying until the request succeeded. After determining the maximum acceptable length, I verified that adding a single character caused the error to manifest. I also confirmed that the client wasn't the issue by sending the same request from a Python app and from Postman. So anyway, I'm confident that, in my case, the length of the payload was my specific problem.
Once again, the source of the problem is anecdotal. The general problem is "Server Says No".
I had the same problem during request to some server. In my case, setting any value to User-Agent in headers in request options helped me.
const httpRequestOptions = {
hostname: 'site.address.com',
headers: {
'User-Agent': 'Chrome/59.0.3071.115'
}
};
It's not a general case and depends on server settings.
This error also can happen when working with http.request, probably your request is not finished yet.
Example:
const req = https.request(options, res => {})
And you always need to add this line: req.end()
With this function we will order to finish sending request.
As in documentation is said:
With http.request() one must always call req.end() to signify the end of the request - even if there is no data being written to the request body.
Also reason can be because of using app instance of express instead of server from const server = http.createServer(app) while creating server socket .
Wrong
const express = require('express');
const http = require('http');
const WebSocket = require('ws');
const app = express();
app.use(function (req, res) {
res.send({ msg: "hello" });
});
const wss = new WebSocket.Server({ server: app }); // will throw error while connecting from client socket
app.listen(8080, function listening() {
console.log('Listening on %d', server.address().port);
});
Correct
const express = require('express');
const http = require('http');
const WebSocket = require('ws');
const app = express();
app.use(function (req, res) {
res.send({ msg: "hello" });
});
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });
server.listen(8080, function listening() {
console.log('Listening on %d', server.address().port);
});
it's been a long time but another case is when performing requests which takes a long time on the server side (more then 2 minutes which is the default for express) and the timeout parameter was not configured in the server side. In my case I was doing client->server->server request (Node.js express) and I should set the timeout parameter on each request router on the server and on the client.
So in both servers I needed to set the request timeout by using
req.setTimeout([your needed timeout])
on the router.
I do both web (node) and Android development, and open Android Studio device simulator and docker together, both of them use port 8601, it complained socket hang up error, after close Android Studio device simulator and it works well in node side. Don’t use Android Studio device simulator and docker together.
There seems to be one additional case here, which is Electron not being a fan of the "localhost" domain name. In my case I needed to change this:
const backendApiHostUrl = "http://localhost:3000";
to this:
const backendApiHostUrl = "http://127.0.0.1:3000";
After that the problem just went away.
This means that DNS resolution (local or remote) might be causing some problems too.
I got a similar error when using CouchDB on OCP cluster.
const cloudantSessionStore = sessionStore.createSessionStore(
{
type: 'couchdb',
host: 'https://' + credentials['host'],
port: credentials['port'],
dbName: 'sessions',
options: {
auth: {
username: credentials['username'],
password: credentials['password']
},
cache: false
}
}
Which should be "http", not "https", to connect with my CouchDB instance. Hope it could be helpful for anyone who is faced with similar issue.
In my case, it was because a application/json response was badly formatted (contains a stack trace). The response was never send to the server.
That was very tricky to debug because, there were no log. This thread helps me a lot to understand what happens.
In case you're using node-http-proxy, please be aware to this issue, which will result a socket hang-up error : https://github.com/nodejitsu/node-http-proxy/issues/180.
For resolution, also in this link, simply move declaring the API route (for proxying) within express routes before express.bodyParser().
Ran into this issue yesterday running my web application and node.js server through IntelliJ IDEA 2016.3.6. All I had to do was clear my cookies and cache in my Chrome browser.
If you are experiencing this error over a https connection and it's happening instantly it could be a problem setting up the SSL connection.
For me it was this issue https://github.com/nodejs/node/issues/9845 but for you it could be something else. If it is a problem with the ssl then you should be able to reproduce it with the nodejs tls/ssl package just trying to connect to the domain
I think worth noting...
I was creating tests for Google APIs. I was intercepting the request with a makeshift server, then forwarding those to the real api. I was attempting to just pass along the headers in the request, but a few headers were causing a problem with express on the other end.
Namely, I had to delete connection, accept, and content-length headers before using the request module to forward along.
let headers = Object.assign({}, req.headers);
delete headers['connection']
delete headers['accept']
delete headers['content-length']
res.end() // We don't need the incoming connection anymore
request({
method: 'post',
body: req.body,
headers: headers,
json: true,
url: `http://myapi/${req.url}`
}, (err, _res, body)=>{
if(err) return done(err);
// Test my api response here as if Google sent it.
})
I my case it's was not an error, but expected behavior for chrome browser. Chrome keeps tls connection alive (for speed i think), but node.js server stop it after 2 min and you get an error.
If you try GET request using edge browser, there will be no error at all.
If you will close chrome window - you will get error right away.
So what to do?
1)You can filter this errors, because they are not really errors.
2)Maybe there is a better solution :)
After a long debug into node js code, mongodb connection string, checking CORS etc, For me just switching to a different port number server.listen(port); made it work, into postman, try that too. No changes to proxy settings just the defaults.
I was using nano, and it took me a long time to figure out this error. My problem was I was using the wrong port. I had port 5948 instead of 5984.
var nano = require('nano')('http://localhost:5984');
var db = nano.use('address');
var app = express();
Might be your server or Socket connection crashes unexpectedly.
I had this error when running two applications on the same port by mistake.
I had a next.js app and another one in nest.js, running both on port 8080, when I looked at the .env files I realized that they had the same port, so I changed the one from nest.js to 3000 and everything worked.
I'm not saying that this is the reason for the error but it's a possibility.
Your problem might also come from an attempt to connect to an HTTP URL while your service is only published on HTTPS...
Definitely a time-consuming mistake!
Got "[GET] localhost:4200, Socket hang up" during Azure Static Web App (SWA) Emulator for Angular app.
Solution is to remove this from angular.json:
"headers": {"cross-origin-opener-policy": "same-origin-allow-popups"}

Resources