My JSON.parse in app.js doesnt function properly - javascript

app.js:
const express = require("express");
const https = require("https");
const app = express();
const port = 3000;
app.get("/",function(req,res){
const url ="https://maps.googleapis.com/maps/api/geocode/jsonaddress=1600+Amphitheatre+Parkway,+Mountain+View,+CA&key=YOUR_API_KEY;
console.log(response.statusCode);
response.on("data",function(data){
var jatin=JSON.parse(data);
console.log(jatin);
})
})
app.listen(port, () => console.log(`Example app listening on port ${port}!`));
Error on Console
app.listen(3000,function(){ console.log("server started on port
3000"); })
server started on port 3000 200 undefined:26
"long_name"
SyntaxError: Unexpected end of JSON input
at JSON.parse ()
at IncomingMessage. (/home/jatin/Downloads/full_stack/Web-Development/maps/app.js:11:21)
at IncomingMessage.emit (events.js:189:13)
at IncomingMessage.Readable.read (_stream_readable.js:487:10)
at flow (_stream_readable.js:931:34)
at resume_ (_stream_readable.js:912:3)
at process._tickCallback (internal/process/next_tick.js:63:19) [nodemon] app crashed - waiting for file changes before starting
The output is visible when I run it on browser but on the console it throws an error.
For some reason JSON.parse() isn't working as expected.
I am trying to make a geocoding API call and in response, it gives me a JSON output...
which when I enter it as a URL on the browser the expected output is received
But when app.js is run on a node express server and when I hit my localhost:3000 I am getting the console error
Apparently the JSON.parse("data") is working but stops unexpectedly. Which leads to error.

You need to have your code to perform JSON.parse on end event instead, like this example form the documentation:
http.get('http://nodejs.org/dist/index.json', (res) => {
const { statusCode } = res;
const contentType = res.headers['content-type'];
let error;
if (statusCode !== 200) {
error = new Error('Request Failed.\n' +
`Status Code: ${statusCode}`);
} else if (!/^application\/json/.test(contentType)) {
error = new Error('Invalid content-type.\n' +
`Expected application/json but received ${contentType}`);
}
if (error) {
console.error(error.message);
// Consume response data to free up memory
res.resume();
return;
}
res.setEncoding('utf8');
let rawData = '';
res.on('data', (chunk) => { rawData += chunk; });
res.on('end', () => {
try {
const parsedData = JSON.parse(rawData);
console.log(parsedData);
} catch (e) {
console.error(e.message);
}
});
}).on('error', (e) => {
console.error(`Got error: ${e.message}`);
});
Notice that this is http.get, but it should be the same for https.get, so in your code the on('data') should be used to assemble the chunks before your perform JSON.parse() on it.
const express = require("express");
const https = require("https");
const app = express();
const port = 3000;
app.get("/", function(req, res) {
const url = "API_URL";
https.get(url, function(response) {
console.log(response.statusCode);
let body = "";
response.on("data", function(data) {
body += data;
});
response.on("end", function() {
console.log(JSON.parse(body));
});
});
res.end("End data response");
});
app.listen(port, () => console.log(`Example app listening on port ${port}!`));
basically .on('end', callback') and .on('data', callback') are event listener to data receive and request end events, and to be able to handle your requests response in node when using http(s).get you have to attache an event listener on data event which is invoked every time your request receives a chunk of the request response, and once the request ended by the service the event end will be invoked stating that there is no more data from the server requested hence the request ended.
as stated in the documentation:
The callback must take care to consume the response data for reasons
stated in http.ClientRequest section.

Related

Check url-redirection using axios in nodejs

I'm using axios for API calling in nodejs.
I want to check if "https://origin.com/?url=https://destination.com" this url is redirecting to "destination.com".
So which status/headers I can check in axios response.
What will be the condition to check if it goes to "destination.com"
var express = require('express');
const axios = require('axios');
var app = express();
app.get('/test', function (req, res) {
// Check if it redirects
axios.get('https://origin.com/?url=https://destination.com')
.then(response => {
console.log(response);
// Here I want to check if it redirects successfully to "destination.com"
if (condition) {
// Successfully redirected to "destination.com"
}
})
.catch(error => {
console.log(error);
});
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
I think you should try to use https for api, then in the response header you can find that it direct to the "destination.com".
Https is much simple and easy to use.
const https = require('https');
https.get('https://encrypted.google.com/', (res) => {
console.log('statusCode:', res.statusCode);
console.log('headers:', res.headers);
res.on('data', (d) => {
process.stdout.write(d);
});
}).on('error', (e) => {
console.error(e);
});
You can find the redirect url under responseURL key,
get fetchedUrl by
const fetchedUrl = response.request.res.responseURL;
see this
Environment node: v8.9.4 axios: ^0.18.0

NextJS, Express, Error during WebSocket handshake: Unexpected response code: 200

The basic problem can be summarized as follows: When creating a Websocket server in Node using ws with the server option populated by an express server(as in this example), while using that same express server to handle the routing for NextJS (as in this example), the upgrade header seems to not be properly parsed.
Instead of the request being routed to the Websocket server, express sends back an HTTP 200 OK response.
I've searched high and low for an answer to this, it may be that I simply do not understand the problem. A possibly related question was brought up in an issue on NextJS's github. They recommend setting WebsocketPort and WebsocketProxyPort options in the local next.config.js, however I have tried this to no avail.
A minimal example of the relevant server code can be found below. You may find the full example here.
const express = require('express')
const next = require('next')
const SocketServer = require('ws').Server;
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}`)
})
const wss = new SocketServer({ server });
wss.on('connection', function connection(ws, request) {
console.log('Client connected');
ws.on('close', () => console.log('Client disconnected'));
});
wss.on('error', function (error) {
console.log(error);
});
setInterval(() => {
wss.clients.forEach((client) => {
client.send(new Date().toTimeString());
});
}, 1000);
}).catch(ex => {
console.error(ex.stack);
process.exit(1);
});
The expected result, of course, is a connection to the websocket server. Instead I receive the following error:
WebSocket connection to 'ws://localhost:3000/' failed: Error during WebSocket handshake: Unexpected response code: 200
Can anyone elucidate anything for me here?
Ok, after more digging I have solved the problem. Quite simply, the ws.Server object to which I was trying to feed the server = express() object is not strictly speaking an http server object. However, server.listen() returns such an http server object. On such an object we can listen for an 'upgrade' call, which we can pass to our ws.Server object's handleUpgrade() event listener, through which we can connect. I will be updating the examples that I linked in my question, but the relevant code is below:
app.prepare().then(() => {
const server = express()
server.all('*', (req, res) => {
return handle(req, res)
})
const wss = new SocketServer({ server });
wss.on('connection', function connection(ws, request) {
console.log('Client connected');
ws.on('close', () => console.log('Client disconnected'));
});
wss.on('error', function (error) {
console.log(error);
});
let srv = server.listen(port, err => {
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
})
srv.on('upgrade', function(req, socket, head) {
wss.handleUpgrade(req, socket, head, function connected(ws) {
wss.emit('connection', ws, req);
})
});

using Node.js' https.request() and outputting to a browser

Im following a article about http requests to nasa's pic of the day. I'm trying to display the JSON object in browser from my server. But all Node.js' examples outputs the api results to a server's console. is it possible to have my server save/forward the response to the browser? I'd like to understand the native http module before relying on any dependencies. Also I'm not sure if it makes a difference but I'm using express to create my server. anything will help even a high level explanation because I'm so confused.
const https = require('https');
app.get('/', (req, res) => {
var url = 'https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY';
var nasa_obj
var request = https.get(url, function (resp) {
var body = '';
resp.on('data', function (chunk) {
body += chunk;
});
resp.on('end', function () {
nasa_obj = JSON.parse(body);
console.log("Got a response: ", nasa_obj);
res.send(nasa_obj)
});
}).on('error', function (e) {
console.log("Got an error: ", e);
});
request.end()
})
UPDATED: CODE IS CORRECT
You only want to send the response once it has been returned to you:
const https = require('https');
app.get('/', (req, res, next) => {
var url = 'https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY';
var nasa_obj
var request = https.get(url, function (response) {
var body = '';
response.on('data', function (chunk) {
body += chunk;
});
response.on('end', function () {
console.log("Got a response: ", body);
res.send(body);
});
}).on('error', function (e) {
console.log("Got an error: ", e);
next(e); // Pass error to error handling middleware
});
request.end()
})
Also make sure you are properly handling errors. Either send back a response to the browser to, as the code above is doing, pass it on to error handling middleware.

NodeJS HTTPs request returns Socket Hang up

const https = require("https");
const fs = require("fs");
const options = {
hostname: "en.wikipedia.org",
port: 443,
path: "/wiki/George_Washington",
method: "GET",
// ciphers: 'DES-CBC3-SHA'
};
const req = https.request(options, (res) => {
let responseBody = "";
console.log("Response started");
console.log(`Server Status: ${res.statusCode} `);
console.log(res.headers);
res.setEncoding("UTF-8");
res.once("data", (chunk) => {
console.log(chunk);
});
res.on("data", (chunk) => {
console.log(`--chunk-- ${chunk.length}`);
responseBody += chunk;
});
res.on("end", () => {
fs.writeFile("gw.html", responseBody, (err) => {
if (err) throw err;
console.log("Downloaded file");
});
});
});
req.on("error", (err) => {
console.log("Request problem", err);
});
returns
// Request problem { Error: socket hang up
// at createHangUpError (_http_client.js:330:15)
// at TLSSocket.socketOnEnd (_http_client.js:423:23)
// at TLSSocket.emit (events.js:165:20)
// at endReadableNT (_stream_readable.js:1101:12)
// at process._tickCallback (internal/process/next_tick.js:152:19) code: 'ECONNRESET' }
http.request() opens a new tunnel to the server. It returns a Writable stream which allows you to send data to the server, and the callback gets called with the stream that the server responds with. Now the error you encountered (ECONNRESET) basically means that the tunnel was closed. That usually happens when an error occured on a low level (very unlikely) or the tunnel timed out because no data was received. In your case the server only responded when you sent something to it, even if it was an empty package, so all you have to do is to end the stream, causing it to get flushed as an empty packet to the server, which causes it to respond:
req.end();
You might want to have a look at the request package which allows you to avoid dealing with such low-level things.

Node js response.write(average size html) takes forever for page to load

This is a simple web scraper.
The HTTP request is sent by NodeJS and response to the client with HTML. The console show body.toString() immediately, but on the browser it loads forever, when I stop the server, it display the page.
I did the similar things in express, it just works, but for some reason, I am not allowed to use express. So I have to write in pure NodeJS.
I have also tried to do it without HTTP request, only left the function response.write and response.end in the if statement, it is fine when I put a few strings in response.write, but when I put minify HTML inside response.write, same situation happen, loading takes forever and display the page when I stop the server.
The following is my code, any help is appreciated, thanks in advance.
const url = require("url"),
http = require('http');
const port = 3000;
const requestHandler = (request, response) => {
if (request.url === "/") {
const options = {
"method": "GET",
"hostname": "something.com",
"port": null,
"path": "/",
"headers": {
"content-type": "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW",
}
};
const req = http.request(options, function (res) {
let chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
let body = Buffer.concat(chunks);
console.log(body.toString());
const html = body.toString();
response.write(html);
response.end();
});
});
req.write("");
req.end();
}
}
const server = http.createServer(requestHandler)
server.listen(port, (err) => {
if (err) {
return console.log('something bad happened', err)
}
console.log(`server is listening on ${port}`)
})

Categories