express req.pipe() does not work - node.js

I want to listen to incoming POST request in express.
I want to pipe this request to another server
I want to receive response inside express handler (I dont want to pipe response to express res stream)
For now I have following code:
app.post('server1',function(req,res,next){
var request = require('request');
req.pipe(request.post('server2')).pipe(res);
}
So this does not work - request is not even piped to server2 - I checked it and there is no incoming request.
I solved points 1 & 2 like this:
var bodyParser = express.bodyParser();
app.use(function(req,res,next){
if(req.path == '/server1' && req.method == 'POST') {
return next();
}
else {
bodyParser(req,res,next);
}
});
Not very nice but it works - it just disables bodyparser for a single route (POST /server1).
But I still don't know how to obtain json response body from piped request - I have following code:
app.post('/server1',function(req,res,next){
var request = require('request');
var pipe = req.pipe(request.post('/server2'));
pipe.on('end',function(){
var res2 = pipe.response;
console.log(res2);
});
});
res2 object has correct statusCode and headers and so on but it does not contain body - how I can get this from the res2 object? /server2 returns some data in json but I dont know how to read it from response...

It doesn't work because bodyParser intercepts all the bodies with parsers

I think you're almost there. You should listen on data events on the pipe to collect the response:
app.post('/server1',function(req,res,next) {
var request = require('request');
var pipe = req.pipe(request.post('/server2'));
var response = [];
pipe.on('data',function(chunk) {
response.push(chunk);
});
pipe.on('end',function() {
var res2 = Buffer.concat(response);
console.log(res2);
// don't forget to end the 'res' response after this!
...
});
});
However, since you solved the "bodyParser() getting in the way" problem, you can also use your initial pipe setup if you just want to return the response generated by server2 (also, be sure to use proper URL's when using request).

Related

POST from Slack for button interactions has empty body

I'm setting up a Slack bot using node.js. The event system works perfectly and gives me POSTs with valid bodies from Slack, and I am able to successfully send messages (both interactive and not) to Slack.
However, the POSTs Slack sends me in response to an interaction with the buttons on interactive messages has an empty body. Interestingly, the Slack headers are still well-formed, although it fails to pass the signing secret test (which I know I implemented properly since event POSTs from Slack pass it).
I've set up everything for interactions according to Slack's own documentation here: https://api.slack.com/messaging/interactivity/enabling. I'm using express, request, and XMLHttpRequest to receive and send HTTP methods. If anyone has encountered this problem or has any insights, that would be great. Thanks!
Here's a code snippet for my function receiving POSTs from interactions:
var express = require('express');
var request = require('request');
var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.json());
app.post('/interaction', (req, res) => {
res.sendStatus(200);
var payload = {
"channel": req.body.payload.channel, // Breaks here since req.body is empty
"text": "Selected choice " + req.body.payload.actions.text.text
}
var r = new XMLHttpRequest();
r.onload = () => { var status = request.status; var data = request.responseText; }
r.open("POST", request_url, true);
r.setRequestHeader("Content-Type", "application/json");
r.setRequestHeader("Authorization", "Bearer " + botToken);
r.send(JSON.stringify(payload));
});
The Slack documentation doesn't seem to mention this, but empirically it would seem that the content type for webhook calls to apps uses Content-Type: application/x-www-form-urlencoded. You'll want to add:
app.use(bodyParser.urlencoded({ extended: true }));
In addition, the payload parameter can't be accessed as you're doing: it's actually a JSON object serialized as a string. This is documented here: https://api.slack.com/messaging/interactivity/enabling#understanding_payloads
The request will be made to your specified request URL in an HTTP POST. The body of that request will contain a payload parameter. Your app should parse this payload parameter as JSON.
So your code will want to do something like this:
var slack_payload = JSON.parse(req.body.payload);
var payload = {
"channel": slack_payload.channel,
"text": "Selected choice " + slack_payload.actions.text.text
}

nodejs pipe https response to request.post and write file

I am Making http proxy program that check http url and If It is download link(content-type:octet-stream), I would get response and relay that response to other computer by using request.post and other computer download file with response that are given by http proxy.
Let's suppose that web proxy computer is A. And It is part of code of A. 192.168.5.253
if(contentType && (contentType== "application/octet-stream" || contentType == "application/gzip")){
console.log("remoteRes##app",remoteRes);
let filepath = req.url.split('/');
let FileName = getFilename(remoteRes, filepath);
let writeStream = fs.createWriteStream(FileName);
/*remoteRes is octect-stream response.
I can get file buffer If I use remoteRes.on(data, chunk => {...})*/
remoteRes.pipe(writeStream); //It works but I want to send file buffer to B without writing file.
.........
I can download file in A. but I want to send this response to pc B(192.168.5.32:10001) server.
So I want to streaming like this:
remoteRes.pipe(request.post('http://192.168.5.32:10001/upload));
And this is part of Server B(192.168.5.32) code
router.post('/upload', (req, res, next) => {
let wstream = fs.createWriteStream('ffff.txt');
req.pipe(wstream); //It dosen't work, but I want to do like this.
})
I want to get filebuffer in router.post('/upload'). It dosen't matter If It is post or put.
I saw that when I use remoteRes.pipe(request.post('http://192.168.5.32:10001/upload));
,I saw that request from ServerA get to ServerB. But I couldn't get file buffer in ServerB.
In short, I want to pipe response to request.post.
You need to store the incoming buffers using your own middleware, so it will be available in the routers request handler
Here you have a working example (you can save it and test it as a single file) :
//[SERVER B]
const express = require('express'); const app = express()
//:Middleware for the incoming stream
app.use(function(req, res, next) {
console.log("[request middleware] (buffer storing)")
req.rawBody = ''
req.on('data', function(chunk) {
req.rawBody += chunk
console.log(chunk) // here you got the incoming buffers
})
req.on('end', function(){next()})
});
//:Final stream handling inside the request
app.post('/*', function (req, res) {
/* here you got the complete stream */
console.log("[request.rawBody]\n",req.rawBody)
});
app.listen(3000)
//[SERVER A]
const request = require('request')
request('http://google.com/doodle.png').pipe(request.post('http://localhost:3000/'))
I hope you can extrapolate this for your specific use case.

Setting the Response Header Using Express Node

I am using the following code to set the response header:
var express = require("express");
var app = express();
app.get("/",function(req,res){
res.header('Content-Type','application/json');
var task = { title :"Do the grocery" }
res.send(JSON.stringify(task));
});
When I see in my response in Google Chrome I don't see the response header "Content-Type" being set. Am I doing something wrong?
That's not a method afaik, should be:
res.set('Content-Type', 'application/json');
As a sidenote, if you call res.json() you can just pass it an object and it'll json stringify it for you.

Node JS: Where is my POST data?

I have no lack with sending POST request to node js server. I have a simple request and a simple server.
My server code is:
var http = require('http');
var bodyParser = require('body-parser');
http.createServer(function (req, res) {
console.log(req.body);
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/')
my client request code is:
var val = JSON.stringify({ city:"SomeCity", name:"MyNameIsHere" });
alert(val);
$.ajax({
url: 'http://127.0.0.1:1337',
type: 'POST',
data: { value: val},
success: function(result) {
alert('the request was successfully sent to the server');}
});
So I suppose to get SomeCity and MyNameIsHere strings in the request body at the node js server, but the req.body field is undefined. Have to say that I open my test.html with request code locally with URL like this:
file:///D:/Projects/test.html
May be Im blind and overseen something trivial, but I have no idea what:)
Have to say that I open my test.html with request code locally with URL like this:
file:///D:/Projects/test.html
You're trying to post cross-domain, which you cannot do in this case. Serve your HTML over HTTP so that you can make a POST. If you use your browser's development tools, you will see that the request will never hit your Node.js server (except for a possible pre-flight request for CORS).
Another problem is that you're not actually using body-parser. If you want the post data, you will have to read from req like a stream.
You are including "body-parser" in var bodyParser = require('body-parser');, but you never actually use it. It won't magically parse the request for you. The default request object does not have a body property... see the documentation.
If you want to use the body-parser module, you should probably use express.js and read the documentation on how to connect it as middleware.
If you want to get the body using the built-in http server, you need to consume the request object first using something like this:
if (req.method == 'POST') {
var body = '';
req.on('data', function(data) {
body += data;
if (body.length > 1000000) {
req.connection.destroy();
}
});
req.on('end', function () {
console.log(req.body);
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
});
}
Adding express library and bodyparser as middleware did the trick. However I could use the code from neelsg answer but working with built-in http server and handling Post data by my own is too burdensome.
So piece of my working code is here:
var express = require('express');
var http = require('http');
var url = require('url');
var bodyParser = require('body-parser');
var app = express();
app.use(express.bodyParser(
{
keepExtensions: true,
limit: 30*1024*1024 // lets handle big data
}
));
app.use(bodyParser.urlencoded());
Bodyparser by default can handle only 100Kb data in the post request, so I had to increase limit using its config options.

how to find request parameters in 'nodejs'

when i sent a request to nodejs server,
how can we find the parameters sent in the request query when request sent to nodejs server.
req.param
req.params
req.query
all giving undefined.
also when i stringify req request it gives error :
Converting circular structure to JSON
How to find query parameters.
You can use the url module:
$ npm install url
And then something like this:
var http = require("http");
var url = require("url");
http.createServer(function(req, res) {
var parsedUrl = url.parse(req.url, true); // true to get query as object
var queryAsObject = parsedUrl.query;
console.log(JSON.stringify(queryAsObject));
res.end(JSON.stringify(queryAsObject));
}).listen(8080);
console.log("Server listening on port 8080");
Test in your browser:
http://localhost:8080/?a=123&b=xxy
For POST requests you can use bodyParser.

Resources