Zombie + NodeJS + Express - Errors while working with tabs - javascript

I'm building a small application using Zombie.js, but tabs dont seem to work properly. My current code follows:
// libs used
var Zombie = require("zombie");
var assert = require("assert");
var http = require('http');
var express = require('express');
var bodyParser = require('body-parser');
// server port and host configs
var server_port = 7777;
var server_ip_address = '127.0.0.1'
var app = express();
var httpServer = http.Server(app);
app.use( bodyParser.json() ); // to support JSON-encoded bodies
app.use( bodyParser.urlencoded() ); // to support URL-encoded bodies
// o navegador
var browser = null,
result = "",
SITE_URL = 'http://en.wikipedia.org/wiki/Programming_language';
app.get('/', function (response, request) {
console.log('GET request received.');
console.log('Opening new tab: ' + SITE_URL);
// opens a tab
browser.open(SITE_URL);
// gets page content
result = browser.html('#content');
console.log('Tab open: '+browser.tabs.index);
console.log('Content: '+result);
request.send(result);
});
httpServer.listen(server_port, server_ip_address, function() {
console.log('Listening on ' + server_ip_address + ':' + server_port);
// creates the browser.
browser = new Zombie();
});
But browser.html('#content'); returns nothing. It seems to me that those tabs are open, but when I try to extract data from the current open tab, by using the browser object, it never works.
Am I doing the right way? Whats the 'right way' of working with tabs in Zombie 2.0.8 ? I just cant find any information/tutorial and the oficial docs arent clear enough for me.
EDIT:
As pointed by P.scheit, open(url) was not enough. Heres the main resulting code:
app.get('/', function (request, response) {
console.log('GET request received.');
if (request.query.url && request.query.selector) {
console.log('Opening new tab: ' + request.query.url);
browser.open(request.query.url);
browser.visit(request.query.url, function () {
result = browser.html(request.query.selector);
console.log('Loaded tab content. Sending back to user...');
response.send(result);
});
console.log('Tab open: '+browser.tabs.index);
} else if (request.query.tabid && request.query.selector) {
var tabid = request.query.tabid;
if (tabid < browser.tabs.length) {
browser.tabs.current = tabid;
console.log('Retrieving content of tab '+tabid+", sending back to user...");
result = browser.html(request.query.selector);
response.send(result);
} else {
console.log('Tab not found!');
response.send('Tab not found!');
}
} else {
console.log('Supply either [(the tab id) AND (search selector)] or [(the url to visit) AND (search selector)]!');
response.send('Supply either [(the tab id) AND (search selector)] or [(the url to visit) AND (search selector)]!');
}
});
After running the server, open some tabs:
$ curl "http://127.0.0.1:7777/?url=http://en.wikipedia.org/wiki/Programming_language&selector=h1"
$ curl "http://127.0.0.1:7777/?url=http://stackoverflow.com/users/3739186/cyberpunk&selector=h1"
$ curl "http://127.0.0.1:7777/?url=http://www.google.com.br&selector=a"
Data from tab 0:
$ curl "http://127.0.0.1:7777/?tabid=0&selector=a"

Just guessing wildly here: did you try using visit after opening the tab? I'm not quite sure if zombie is requesting the site when you pass the url to open.

Related

Document is not defined on node.js - How can i import a variable from another .js file to node.js server?

Edit: Actually, my problem is "How to use "value" from selection.js in the server.js ? " I want to direct user to a searching page according to his/her choice .
i am new at web programming. I have server.js and a selection.js.
server.js is a node file, and my server is in it. selection.js is my item class changer. I am changing selected item's class with selection.js and i am trying to use this selected item from server.js. When i try below codes, i am taking this shit: Document is not defined on node.js
It is really painful. I am trying to solve it about hours. But, nothing!
Pls, help me :/
selection.js :
var iconContainer = document.getElementById('iconContainer');
var icon = iconContainer.getElementsByClassName("item");
for (var i = 0; i < icon.length; i++) {
icon[i].addEventListener("click", function() {
var current = document.getElementsByClassName("active");
current[0].className = current[0].className.replace(" active", "");
this.className += " active";
const btnSearch = document.querySelector("#btnSearch");
btnSearch.addEventListener("click", () => {
// get the active item's value
const value = document.querySelector(".item.active span").innerText;
console.log("value: ", value);
// do fetch
});
});
}
module.exports={searchPath: "/"+value};
server.js:
var fs = require('fs');
var express = require('express');
var app = express();
var path = require('path');
app.use('/public', express.static(path.join(__dirname, 'public')));
// '/' girdisi için index.html getirilecek.
app.get('/', function (req, res) {
fs.readFile('index.html', function(err, data) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(data);
res.end();
});
});
//---------------------------------------------------
// Server kuruyoruz.
var server = app.listen(8081,"127.0.0.1", function () {
var host = server.address().address;
var port = server.address().port;
console.log('Server http://' + host + ':' + port+' adresinde çalışıyor...');
});
var search = require('./public/js/selection');
console.log(search.searchPath);
So, the code you label as selection.js needs to be in your web page, either directly embedded or linked from a <script> tag so it can run in the web page in the browser.
Then, that code can make an Ajax call using the XMLHttpRequest or fetch() interfaces in the browser to a route on your server and pass the desired value.
That route on your server (which you need to define and add code for) can then examine that value and decide what data to return the the Ajax call.
Your Javascript in the web page, then receives that returned data from the Ajax call and decides what to do with it such as insert new content in the page for the user to see, cause the browser to load a different page or refresh the current page or whatever else is appropriate.

Node js Error: Protocol "https:" not supported. Expected "http:"

I am using IBM Bluemix to make a web service for a school project.
My project needs to request a JSON from an API, so I can use the data it provides. I use the http get method for a data set, and I am not sure if it is working properly.
When I run my code, I get the message:
Error: Protocol "https:" not supported. Expected "http:"
What is causing it and how can I solve it?
Here is my .js file:
// Hello.
//
// This is JSHint, a tool that helps to detect errors and potential
// problems in your JavaScript code.
//
// To start, simply enter some JavaScript anywhere on this page. Your
// report will appear on the right side.
//
// Additionally, you can toggle specific options in the Configure
// menu.
function main() {
return 'Hello, World!';
}
main();/*eslint-env node*/
//------------------------------------------------------------------------------
// node.js starter application for Bluemix
//------------------------------------------------------------------------------
// HTTP request - duas alternativas
var http = require('http');
var request = require('request');
// cfenv provides access to your Cloud Foundry environment
// for more info, see: https://www.npmjs.com/package/cfenv
var cfenv = require('cfenv');
//chama o express, que abre o servidor
var express = require('express');
// create a new express server
var app = express();
// serve the files out of ./public as our main files
app.use(express.static(__dirname + '/public'));
// get the app environment from Cloud Foundry
var appEnv = cfenv.getAppEnv();
// start server on the specified port and binding host
app.listen(appEnv.port, '0.0.0.0', function() {
// print a message when the server starts listening
console.log("server starting on " + appEnv.url);
});
app.get('/home1', function (req,res) {
http.get('http://developers.agenciaideias.com.br/cotacoes/json', function (res2) {
var body = '';
res2.on('data', function (chunk) {
body += chunk;
});
res2.on('end', function () {
var json = JSON.parse(body);
var CotacaoDolar = json["dolar"]["cotacao"];
var VariacaoDolar = json["dolar"]["variacao"];
var CotacaoEuro = json["euro"]["cotacao"];
var VariacaoEuro = json["euro"]["variacao"];
var Atualizacao = json["atualizacao"];
obj=req.query;
DolarUsuario=obj['dolar'];
RealUsuario=Number(obj['dolar'])*CotacaoDolar;
EuroUsuario=obj['euro'];
RealUsuario2=Number(obj['euro'])*CotacaoEuro;
Oi=1*VariacaoDolar;
Oi2=1*VariacaoEuro;
if (VariacaoDolar<0) {
recomend= "Recomenda-se, portanto, comprar dólares.";
}
else if (VariacaoDolar=0){
recomend="";
}
else {
recomend="Recomenda-se, portanto, vender dólares.";
}
if (VariacaoEuro<0) {
recomend2= "Recomenda-se, portanto, comprar euros.";
}
else if (VariacaoEuro=0){
recomend2="";
}
else {
recomend2="Recomenda-se,portanto, vender euros.";
}
res.render('cotacao_response.jade', {
'CotacaoDolar':CotacaoDolar,
'VariacaoDolar':VariacaoDolar,
'Atualizacao':Atualizacao,
'RealUsuario':RealUsuario,
'DolarUsuario':DolarUsuario,
'CotacaoEuro':CotacaoEuro,
'VariacaoEuro':VariacaoEuro,
'RealUsuario2':RealUsuario2,
'recomend':recomend,
'recomend2':recomend2,
'Oi':Oi,
'Oi2':Oi2
});
app.get('/home2', function (req,res) {
http.get('https://www.quandl.com/api/v3/datasets/BCB/432.json?api_key=d1HxqKq2esLRKDmZSHR2', function (res3) {
var body = '';
res3.on('data', function (chunk) {
body += chunk;
});
res3.on('end', function () {
var x=json.dataset.data[0][1];
console.log("My JSON is "+x); });
});
});
});
});
});
Here is a print of the error screen I get:
When you want to request an https resource, you need to use https.get, not http.get.
https://nodejs.org/api/https.html
As a side note to anyone looking for a solution from Google... make sure you are not using an http.Agent with an https request or you will get this error.
The reason for this error is that you are trying to call a HTTPS URI from a HTTP client. The ideal solution would have been for a generic module to figure out the URI protocol and take the decision to use HTTPS or HTTP internally.
The way I overcame this problem is by using the switching logic on my own.
Below is some code which did the switching for me.
var http = require('http');
var https = require('https');
// Setting http to be the default client to retrieve the URI.
var url = new URL("https://www.google.com")
var client = http; /* default client */
// You can use url.protocol as well
/*if (url.toString().indexOf("https") === 0){
client = https;
}*/
/* Enhancement : using the URL.protocol parameter
* the URL object , provides a parameter url.protocol that gives you
* the protocol value ( determined by the protocol ID before
* the ":" in the url.
* This makes it easier to determine the protocol, and to support other
* protocols like ftp , file etc)
*/
client = (url.protocol == "https:") ? https : client;
// Now the client is loaded with the correct Client to retrieve the URI.
var req = client.get(url, function(res){
// Do what you wanted to do with the response 'res'.
console.log(res);
});
Not sure why, but the issue for me happened after updating node to version 17, i was previously using version 12.
In my setup, i have node-fetch using HttpsProxyAgent as an agent in the options object.
options['agent'] = new HttpsProxyAgent(`http://${process.env.AWS_HTTP_PROXY}`)
response = await fetch(url, options)
Switching back to node 12 fixed the problem:
nvm use 12.18.3
I got this error while deploying the code.
INFO error=> TypeError [ERR_INVALID_PROTOCOL]: Protocol "https:" not supported. Expected "http:"
at new NodeError (node:internal/errors:372:5)
To fix this issue, I have updated the "https-proxy-agent" package version to "^5.0.0"
Now the error was gone and it's working for me.

Why the node.js script is call twice?

I am a beginner in Node.js
I write the first script in Node.js like the below:
var count = 0;
var http = require('http');
var serv = http.createServer(function (req, res) {
count++;
console.log("why two?:" + count);
res.writeHead(200,{'Content-Type': 'text/html'});
require('colors');
if (count % 2 == 0) {
console.log('count:' + count);
console.log('smashing node'.rainbow);
res.end('<marquee>Smashing Node</marquee>');
} else {
console.log('count:' + count);
console.log('WTF'.rainbow);
res.end('<h4>Smashing Node</h4>');
}
});
serv.listen(3000);
Then I run this script
node first.js
In browser, access http://localhost:3000
And the result in console is:
why two?:1
count:1
WTF
why two?:2
count:2
smashing node
Why the code is called twice?
Thanks
Because two requests are being made.
Probably one is for / and the other is for /favicon.ico.
Your code doesn't care what the path is when it handles a request.
You can test that by looking in the Net tab of your browser's developer tools or examining the contents of the req object.
That anonymous function is called whenever you request on http://localhost:3000
So maybe somehow you're requesting twice (e.g. for / and /favicon.ico)
Try opening chrome dev tools, and in console tab you'll maybe see an error, that favicon.ico wasn't found.
or you can use morgan to keep track of requests:
var app = require('express')();
var morgan = require('morgan');
app.use(morgan('dev'));
It will log every request, with codes and URL-s. It needs express though.
var count = 0;
var http = require('http');
var serv = http.createServer();
serv.on('request',function(req,res){
count++;
console.log("why two?:" + count);
res.writeHead(200,{'Content-Type': 'text/html'});
if (req.url=='/') {
console.log(req.method);
console.log(req.headers);
console.log(req.url);
res.end('<marquee>Smashing Node</marquee>');
}
});
serv.listen(3000);
in this it checks only for the '/' url and then responds....so the marquee is returned

Why does my websocket close after a few minutes?

I'm using ws with node.js on the server side and the regular WebSocket API on the client side. Opening the connection and messaging a few times back and forth works fine. But the socket always closes after a minute or two. Aren't they supposed to persist? Am I doing something wrong?
My server is node.js hosted on heroku. I just tested locally again using foreman start (the heroku tool to run the server locally) and the socket doesn't close unexpectedly at all, so perhaps it's a misconfiguration on heroku. Anyway, here's a relevant code sample with a few functions omitted for brevity.
I'm testing the application in Chrome on OSX Yosemite but have seen the same behavior in Chrome on Windows 7 when running against production environment.
server:
// Client <-> Host Protocol functions. Move to a different file so that they can be shared.
var C2H_SIGNAL_TYPE_REGISTER = "register";
var H2C_SIGNAL_WELCOME = "welcome";
var H2C_SIGNAL_TYPE_ERROR = "error";
var H2C_SIGNAL_TYPE_PEER_ADDED = "peer_joined";
var H2C_SIGNAL_TYPE_PEER_LEFT = "peer_left";
// Update channel endpoint names.
var UPDATE_ENDPOINT_PEERS = "/peers";
// Create a signal message with all asociated default properties.
// Signal senders should create this object and update it accordingly when
// building a signal message to send to a peer.
function createHostMsg(type)
{
var msg = { signalType: type };
if ( type == H2C_SIGNAL_WELCOME ) {
// Since we're sending a welcome message, we need to provide a list
// of currently connected clients.
msg.peers = {};
for ( var addr in clients ) {
console.log("addr " + addr);
var c = clients[addr].description;
if ( c && c.id ) {
msg.peers[c.id] = c;
}
}
}
return msg;
}
// require modules.
var express = require('express');
var http = require('http');
var bodyParser = require('body-parser');
var multer = require('multer');
// Tracks connected peers.
var clients = { };
// 1. Configure the application context settings.
var app = express();
app.enable('trust proxy');
app.use(express.static(__dirname + '/public'));
app.use(bodyParser.json()); // parse json
app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
app.use(multer()); // for parsing multipart/form-data
// a. configure http routers. these will handle requests coming from app.
app.set('port', (process.env.PORT || 5000));
app.get('/app', peerApp);
app.get('/script/:name', publicScriptRouter);
// 2. Create the http server itself, passing app to be the request handler.
// app will handle routing and multiplexing of incoming requests to different
// route middleware handlers.
var http = require('http');
var WebSocketServer = require("ws").Server
var httpServer = http.createServer(app);
httpServer.listen( app.get('port') );
// 3. Create one of these for all socket endpoints.
var wss = new WebSocketServer( { server: httpServer, path: UPDATE_ENDPOINT_PEERS } );
wss.on("connection", function(webSocket) {
// 1. Associate the socket with the remote address it came from.
var remoteAddress = webSocket._socket.remoteAddress;
var remotePort = webSocket._socket.remotePort;
var clientConnID = remoteAddress + ":" + remotePort;
var exists = clients[clientConnID] != null;
if ( exists ) {
console.log("socket server connection: associating new connection from %s with registered peer.", clientConnID);
clients[clientConnID].socket = webSocket;
} else {
console.log("socket server connection: associating new connection from %s with unregistered peer.", clientConnID);
clients[clientConnID] = { description: null, socket: webSocket };
}
// 2. Hook up handlers for communication over this particular socket.
webSocket.on("message", function(data, flags) {
processMessage(webSocket, data, flags);
});
webSocket.on("close", function() {
// Praise satin for closures!!
removePeer(clientConnID);
});
});
// Transduce the message and handle it accordingly.
function processMessage(socket, data, flags)
{
var msg = JSON.parse(data);
if ( !msg.signalType ) {
var msg = createHostMsg( H2C_SIGNAL_TYPE_ERROR );
msg.errStr = "message_malformed";
socket.send( JSON.stringify( msg ) );
} else if ( msg.signalType == C2H_SIGNAL_TYPE_REGISTER ) {
handleRegistration(socket, msg);
}
}
client:
function initSignalChannel()
{
rtcPeer.channel = new WebSocket( location.origin.replace(/^http/, 'ws') + "/peers" );
rtcPeer.channel.onmessage = updateChannelMessage;
rtcPeer.channel.onopen = function(event) {
console.log("remote socket opened");
}
rtcPeer.channel.onclose = function(event) {
console.log("host closed remote socket.");
}
}
function updateChannelMessage(event) {
var msgObj = JSON.parse(event.data);
if ( !msgObj || !msgObj.signalType ) {
console.log("updateChannelMessage: malformed response!! %o", msgObj );
} else if ( msgObj.signalType == "welcome" ) {
console.log("updateChannelMessage: received welcome from host.");
handleWelcome(msgObj);
} else if ( msgObj.signalType == "peer_joined" ) {
console.log("updateChannelMessage: received peer_joined from host.");
if ( msgObj.peer.id == rtcPeer.description.id ) {
console.log("updateChannelMessage: peer_joined: received notification that I've been added to the room. " + msgObj.peer.id);
console.log(msgObj);
} else {
console.log("updateChannelMessage: peer_joined: peer %s is now online.", msgObj.peer.id);
console.log(msgObj);
addRemotePeer( msgObj.peer );
}
}
}
function addRemotePeer(peerObj)
{
remotePeers[peerObj.id] = peerObj;
var ui = createPeerUIObj(peerObj);
$("#connectedPeerList").append( ui );
}
function createPeerUIObj(peerObj)
{
var ui = null;
if ( peerObj ) {
ui = $("<li></li>");
var a = $("<a></a>");
a.append("peer " + peerObj.id);
ui.append(a);
ui.click(function(event) { console.log("clicked");});
}
return ui;
}
function handleWelcome(msgObj)
{
if ( msgObj.id ) {
console.log("updateChannelMessage: welcome: received id from host. " + msgObj.id);
console.log(msgObj);
rtcPeer.description.id = msgObj.id;
for ( var p in msgObj.peers ) {
addRemotePeer(msgObj.peers[p]);
}
} else {
console.log("updateChannelMessage: malformed response. no id.");
}
}
Thanks for the comments everyone. It turns out that jfriend00 had the right answer, I just didn't realize that the hosting service I was using wouldn't allow for the connection to be kept open.
From the below forum posting, the solution is
you'll need to make your clients ping the server periodically to keep the socket alive.
Not the most ideal situation, but indeed doable. Thanks for pointing me in the right direction.

Prime the website using Express JS

I really hope to find some answers here as i tried everything by now.
Background:
Overtime we deploy code to web server, we need to do a cache warm up, i.e. access the site and make sure it loads. First load is always the slowest since IIS require to do some manipulations with a new code and cache it.
Task:
Create a page which will a checkbox and a button. Once button is pressed, array of links sent to server. Server visits each link and provides a feedback on time it took to load each page to the user.
Solution:
I am using node JS & express JS on server side. So far i manage to POST array to the server with links, but since i have limited experience with node JS, i can not figure out server side code to work.
Here is a code i got so far (it is bits and pieces, but it gives an idea of my progress). Any help will be greatly appreciated!!!
var express = require("express");
var app = express();
var bodyParser = require('body-parser');
var parseUrlencoded = bodyParser.urlencoded({ extended: false});
var http = require("http");
function siteToPrime(url){
http.get(url, function (http_res) {
// initialize the container for our data
var data = "";
// this event fires many times, each time collecting another piece of the response
http_res.on("data", function (chunk) {
// append this chunk to our growing `data` var
data += chunk;
});
// this event fires *one* time, after all the `data` events/chunks have been gathered
http_res.on("end", function () {
// you can use res.send instead of console.log to output via express
console.log(data);
});
});
};
//Tells express where to look for static content
app.use(express.static('public'));
app.post('/', parseUrlencoded, function(request, response){
var newBlock = request.body;
console.log(Object.keys(newBlock).length);
var key = Object.keys(newBlock)[0];
console.log(newBlock[key]);
siteToPrime("www.google.com");
response.status(201);
});
app.listen(3000, function(){
console.log("Server listening on port 3000...");
});
Assuming that you have access to the array in the post route:
var express = require("express"),
request = require("request"),
app = express();
var start = new Date();
app.use(express.static('public'));
app.use(bodyParser.urlencoded({extended: false}));
function siteToPrime(req, res, urls) {
urls.forEach(function(url)) {
request(url, function(error, res, body) {
if (!error && res.statusCode == 200) {
console.log(url +' : ' + body);
console.log('Request took: ', new Date() - start, 'ms');
}
});
}
res.redirect('/');
};
app.post('/', function(req, res){
var urls = req.body.urls // Array os urls.
siteToPrime(req, res, urls);
});
app.listen(3000, function(){
console.log("Server listening on port 3000...");
});

Categories