Node request() not being sent - javascript

I'm using the npm request library and am running into an issue where the request is never sent if I call express's res.send() after calling request. I realize the request callback won't fire if I close the connection, but I'm not even seeing the request being sent in the first place.
This code is being executed on RunKit (formerly TonicDev), an online code editor that allows code execution via endpoints. I'm not seeing this issue on my local machine, so it seems like it may have to do with RunKit. Anyone have any ideas as to what's going on here or how I might work around this?
You can execute the code yourself by going to:
https://runkit.com/gragland/58056bc6e9d9ed00130c84d5 and clicking the endpoint link at the top.
// Helper to return a RunKit compatible express app (runkit.com/tonic/express-endpoint)
var tonicExpress = require("#runkit/tonic/express-endpoint/1.0.0")
// Provide the exports object to the tonicExpress helper
var app = tonicExpress(module.exports)
var request = require('request')
app.get("/", function(req, res){
var request_number = 9
request({
// To see if request is sent go to: https://requestb.in/1coqbqn1?inspect
url: 'http://requestb.in/1coqbqn1',
method: 'POST',
json: {
request_number: request_number,
message: 'hello'
}
})
// The line below has to be commented out for the above request to be sent
// I don't care about the request callback() firing, I just want the request to be sent
res.send('Done')
})

Related

Is it possible to start a server in Zapier Code

We need to send an HTTP CODE = 200 with a body 'OK' in reply to a notification through Zapier.
Is it possible to use the following code in Zapier:
var http = require('http');
const server = http.createServer((req,res) => {
res.statusCode = 200;
res.end('OK');
}).listen(80);
It returns an error:
Error: You did not define `output`! Try `output = {id: 1, hello: "world"};`
And the reply doesn't work.
David here, from the Zapier Platform team.
To cut to the chase - though it might be possible to start an http server (there's no reason it wouldn't be, as far as I know), it's not going to do what it seems like you're hoping to do. Namely, you can't send a custom response to an incoming webhook. From the docs:
There is no way to customize the response to the request you send to the Catch Hook URL, as the response is sent before the Zap triggers and runs on the webhook request.
If you need behavior like that, I'd suggest running a webserver.
The specific Code step error you're seeing has to do with not defining output to the function. Something goes in and something must come out. You can customize the output based on the input and use that output, but something has to be returned from the function (even if it's just {}).

Why does this nodejs proxy server hang?

In browser javascript is pathetically broken in that the only way to make requests is using script tags and jsonp. To make this useful, I'm trying to make a nodejs server that, given a callback name and address, loads the page at the address and pads it in a call to callback and serves the result. However, I know next to nothing about nodejs. If the server's response is loaded from a script tag it would result in actually loading a web page. Currently, I'm writing the request as localhost:8000/callback/address so a script tag might be <script src="localhost:8000/alert/https://www.google.com" type="text/javascript"></script>. Here is my code for the server:
var http = require("http");
var request = require("request");
var server = http.createServer(function(req, res){
req.on("end", function(){
console.log("alive");
var url = req.url;
var i = url.indexOf("/", 1);
request(url.substring(i + 1), function(err, ret, body){
res.writeHead(200);
res.write(url.substring(1, i) + "(\"" + body + "\");");
res.end();
});
});
});
server.listen(8000);
Why does this stay loading for a very long time but never actually load? By using console.log() it seems as if the req.on("end") callback is never even called.
If you don't care about any request data, you could just add req.resume(); after you add your end event handler.
The reason it's getting "stuck" is that since node v0.10, streams start out in a paused state, so you need to unpause them by reading from them in some way. req.resume(); accomplishes this. Once there is nothing left in the request stream (which there could be nothing), the end event will be emitted.

filter outgoing requests in node.js for logging

I am building an Express app which on certain requests has to make its own HTTP calls. I could use Superagent, request or node's own http.request.
Thing is, I need to log all of those server originating requests and their respective responses. Calling log.info before each and every of those seems silly.
How can you add a pre-filter for all outgoing HTTP calls, and ideally access both req and res?
NOTE: I am not interested in logging requests coming in to the server I am building, only in the requests that the server itself kicks off. Think of my server as a client to another black box server.
What you can do is patch http and https and proxy the request method. This way you can have a global handler that will catch the req & res objects.
var http = require('http');
var https = require('https');
var patch = function(object) {
var original = object.request;
// We proxy the request method
object.request = function(options, callback) {
// And we also proxy the callback to get res
var newCallback = function() {
var res = arguments[0];
// You can log res here
console.log("RES",res.statusCode);
callback.apply(this,arguments);
}
var req = original(options, newCallback);
// You can log your req object here.
console.log(req.method,req.path);
return req;
}
}
patch(http);
patch(https);
http.get("http://www.google.com/index.html", function(res) {
console.log("Got response");
}).on('error', function(e) {
console.log("Got error: " + e.message);
});
Edit: This might work if you use the request npm package as well, as it might just rely on the built-in node.js http.request method anyways.
What server are you going to use for you app?
I would definally bring up such functionality on to server level. Take a look how heroku router is doing it. You can track all of needed information using some of their addons: papertrail, or newrelic ( or use them separately for you app ).
https://papertrailapp.com/
http://newrelic.com/
I like out-of-box solutions in this case, no need extend your app logic for logging such information.
If you want to have your own solution, you can setup nginx to monitor request/response info.
http://nginx.com/resources/admin-guide/logging-and-monitoring/

Meteor: what is the final Location/URL after following redirects?

Meteor's HTTP package is a wrapper around mikeal's request, and it supports the followRedirects option. But how can one find out what the final URL is, after the 3xx redirect responses have been followed (and the request didn't fail because of lack of a cookie jar)?
With request, the final URL is in response.request.href. But with Meteor... ?
Here's the Meteor code:
if (Meteor.isServer) {
Meteor.startup(function () {
var url = 'http://google.com';
var result = HTTP.call("HEAD", url, {
followRedirects: true
});
console.log(result); // nothing here hints at the final URL
});
}
I've created a package that does this - http-more.
Turns out Meteor doesn't pass back the request object within the response, and given the history of rejected PRs concerning enhancements to the HTTP package, I've just implemented that option separately.

Call function in nodejs from angular application

I'm having an angular app(angular-seed app) which should call a function in nodejs(web-server.js).
The function in nodejs is just calls a batch file.
If I understood this correctly you want a click on the client-side (angular app) to call a batch file on the server side. You can do this in several ways depending on your requirements, but basically you want the client-side to send a http-request to the server (either with ajax call or form submit) and process this on the server that will call the batch file.
Client-side
On the client-side you need to have a button that uses the angular ng-click directive:
<button ng-click="batchfile()">Click me!</button>
In your angular controller you'll need to use the $http service to make a HTTP GET request to your server on some particular url. What that url is depends how you've set up your express app. Something like this:
function MyCtrl($scope, $http) {
// $http is injected by angular's IOC implementation
// other functions and controller stuff is here...
// this is called when button is clicked
$scope.batchfile = function() {
$http.get('/performbatch').success(function() {
// url was called successfully, do something
// maybe indicate in the UI that the batch file is
// executed...
});
}
}
You can validate that this HTTP GET request is made by using e.g. your browser's developer tools such as Google Chrome's network tab or a http packet sniffer such as fiddler.
Server-side
EDIT: I incorrectly assumed that angular-seed was using expressjs, which it doesn't. See basti1302's answer on how to set it up server-side "vanilla style" node.js. If you're using express you can continue below.
On the server side you need to set up the url in your express app that will perform the batch file call. Since we let the client-side above make a simple HTTP GET request to /performbatch we'll set it up that way:
app.get('/performbatch', function(req, res){
// is called when /performbatch is requested from any client
// ... call the function that executes the batch file from your node app
});
Calling the batch file is done in some ways but you can read the stackoverflow answer here for a solution:
node.js shell command execution
Hope this helps
The OP didn't mention express so I'll provide an alternative for the server side (Node.js part) without using any additional frameworks (which would require installing it via npm). This solution uses just node core:
web-server.js:
'use strict';
var http = require('http')
var spawn = require('child_process').spawn
var url = require('url')
function onRequest(request, response) {
console.log('received request')
var path = url.parse(request.url).pathname
console.log('requested path: ' + path)
if (path === '/performbatch') {
// call your already existing function here or start the batch file like this:
response.statusCode = 200
response.write('Starting batch file...\n')
spawn('whatever.bat')
response.write('Batch file started.')
} else {
response.statusCode = 400
response.write('Could not process your request, sorry.')
}
response.end()
}
http.createServer(onRequest).listen(8888)
Assuming you are on Windows, I would at first use a batch file like this to test it:
whatever.bat:
REM Append a timestamp to out.txt
time /t >> out.txt
For the client side, there is nothing to add to Spoike's solution.

Categories