I'm attempting to write a simple service will
Receive a http request
Modify some values in the body
Then, post the data(headers + newly modified body) to another endpoint.
return the exact response from the new request to the client.
I have found a sample that does the http relay nicely, but I'm struggling with modifying the post before it's sent on? I'm able to get the contents of the post, but can seem to get my head around how to modify it before sending it on it's way.
var http = require( 'http' );
var qs = require( 'querystring' );
http.createServer( function ( req, resp ) {
var h = req.headers;
h.host = "webdbg.com";
req.url = "/sandbox/FileForm.asp";
var newRequest = http.request( {
host: h.host, port: 80, path: req.url, method: req.method, headers: h
}, function ( newResp ) {
resp.writeHead( newResp.statusCode, newResp.headers );
//as we receive our response from the new request, start writing it to this response.
newResp.on( 'data', function ( respBody ) { resp.write( respBody ); });
//once we have all the data from the new request stor writing it to this response.
newResp.on( 'end', function () { resp.end(); });
});
var postData = "";
//as we receive our body write it to the new request.
req.on( 'data', function ( reqBody ) { postData += reqBody; newRequest.write( reqBody )});//here I need to replace the values of the form post
//once we have all of our data from this request, stop writing it to the new request.
req.on( 'end', function () { console.log(qs.stringify(qs.parse(postData))); newRequest.end(); });
}).listen(1337);
console.log( "Server running...");
I'm coming over from the dark side(C#) and as most, I'm struggling with the asynchronous nature of Node.js. With that, I'm committed to plugging away at the tutorials on Node School and Plural Sight until I get it! Any help you can provide with this would greatly be appreciated.
You want to modify the response and relay it to the client?
Change the newResponse handler to modify the response from the remote server.
newResp.on( 'data', function ( respBody ) { resp.write( respBody ); });
to
newResp.on( 'data', function ( respBody ) { resp.write( MODIFY(respBody) ); });
Related
for my current project I have to send form-data from my lambda function to an api endpoint. The api endpoint essentially expects two images (that it compares with one another) and a key. As mentioned before, I somehow seem unable to send the correct form-data to the api endpoint. I checked out postman, and it seems to have worked alright, but something doesn't seem to work in my function. I presume it must be related the form-data string that I'm sending. Below you can find a shortened version of the function (I excluded the two image files), but somehow I'm getting an error back telling me that the api cannot read the key property:
const http = require('http');
const https = require('https');
const httpPromise = (protocol, params, postData) => {
return new Promise((resolve, reject) => {
const requestModule = protocol === 'http' ? http : https;
const req = requestModule.request(params, res => {
// grab request status
const statusCode = res.statusCode;
if(statusCode < 200 || statusCode > 299) {
throw new Error('Request Failed with Status Code:', statusCode);
}
let body = '';
// continuosly update data with incoming data
res.setEncoding('utf8');
res.on('data', data => body += data);
// once all data was received
res.on('end', () => resolve(body));
})
// write data to a post request
if(typeof(params.method) === 'string' && params.method === 'POST' && postData) {
req.write(postData)
}
// bind to the error event
req.on('error', err => reject(err));
// end the request
req.end();
})
}
const controller = async () => {
const apiKey = "00000000";
const options = {
hostname: '***"
port: 80,
path: '***'
method: 'POST',
headers: {"content-type": "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW"}
}
const postData = "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"key\"\r\n\r\00000000\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--"
let result = await httpPromise('http', options, postData)
console.log(result);
}
yeah, so somehow it just doesn't seem to recognise the key in the postData string. I have tried various different combinations but just can't seem to get this to work.
The default http and https libraries are kind of wordy and annoying.
Would recommend using the request library instead. Read more here
In which case, to make the request, you can simply write it as :
var request = require('request');
var formData = {
// Pass a simple key-value pair
my_field: 'my_value',
}
request.post({url:'http://service.com/upload', formData: formData}, (err, response, body) => {
// Handle response here
});
Alright, so for anyone who might also face the same issue, it took me a little but figured out what the issue was. I didn't set the Content-Length header, which then in turn meant that node automatically added the Transfer-Encoding Header and set its value to chunk. This broke the receiving api and resulted in the issue. Setting the Content-Length header to the correct length and setting the Transfer-Encoding Header to an empty string solved my issue here (but I think one could also simply omit the transfer-encoding header once you defined the Content-Length Header).
I am trying to post my form data to server(node) but it is not getting reached there when i put console to data in backend it says undefined.Data is been sent from client but not reached in server.I think i am wrong at headers,can any one please suggest help.
my ts,
var headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded')
this.http.post(this.header1+'login', JSON.stringify(form), { headers: headers })
my server,
exports.login = function( req, res ) {
console.log("Params:"+req.body.email);
//console.log('email:'+params.email);
var query = 'select * from profile where email = ? and password = ?';
connection.query(query,[req.body.email,req.body.password],function(error,result,rows,fields){
if(!!error){console.log(error)
console.log('fail');
}else{
console.log(result);
res.send(result);
}
// }
});}
my routes(express)
router.post('/login', admin.login);
http uses Observable and observables are lazy. They don't actually execute anything unless subscribed to.
You need either
this.http.post(this.header1+'login', JSON.stringify(form), { headers: headers })
.subscribe(response => console.log(response.json());
this.http.post(this.header1+'login', JSON.stringify(form), { headers: headers })
.toPromise();
to make http send the request.
I have to POST to an API that someone else has developed in order to obtain an authorization code, and as I have to do it in several different contexts I thought I'd move the code for handling the POST and getting the response to a service.
The frustrating thing at the moment is that I seem to be getting back the value that I want from the API, but can't return it from the server to the calling sails controller.
Here's the service source code:
module.exports = {
getVerifyCode: function(uuid, ip_addr) {
console.log (uuid);
console.log (ip_addr);
var http = require('http'),
querystring = require('querystring'),
// data to send
send_data = querystring.stringify({
uuid : uuid,
ip_addr : ip_addr
}),
// options for posting to api
options = {
host: sails.config.api.host,
port: sails.config.api.port,
path: '/verifyCode/update',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(send_data)
}
},
json_output = "",
// post request
post_req = http.request(options, function(post_res) {
post_res.on('data', function(chunk) {
json_output += chunk;
});
post_res.on('end', function() {
var json_data = JSON.parse(json_output),
verify_code = json_data.verify_code;
console.log("code="+verify_code);
return ('vc='+verify_code);
});
});
post_req.write(send_data);
post_req.end();
}
}
And here's two relevant lines from my controller action:
var vc = verify.getVerifyCode(req.session.uuid, req.connection.remoteAddress);
console.log('vc='+vc);
The weird thing is that the controller console log gets written before the service one does:
vc=undefined
code=YoAr3ofWRIFGpoi4cRRehP3eH+MHYo3EogvDNcrNDTc=
Any ideas? I have a much simpler service running (just some string manipulation stuff); I have a feeling the issue here relates to the asynchronous nature of the API request and response.
Jasper, your correct in your assumption that it is the " asynchronous nature of the API request and response".
When you execute your http call in your verify service, node makes that call and them moves on to the rest of the code console.log('vc='+vc); and does not wait for the http call to finish.
I'm not sure what your end result should be but you can rewrite your controller / service to include the callback (this is just one options, there are many ways to do this of course, other people should suggest others)
verify.js
getVerifyCode: function(uuid, ip_addr, cb) {
// Bunch of stuff
return post_req = http.request(options, cb(post_res});
}
then in your controller
controller.js
verify.getVerifyCode(req.session.uuid, req.connection.remoteAddress, function(resps){
// code in here to execute when http call is finished
})
I have this basic server:
var http = require("http");
var url = require("url");
var routing = require("./RoutingPath");
function start() {
function onRequest(request, response) {
var path = url.parse(request.url).pathname;
var query = url.parse(request.url,true).query;
routing.Route(path.toLowerCase(), query, function(recordset){
response.writeHead(200, {"Content-Type": "application/json"});
if (recordset != null)
{
console.log(JSON.stringify(recordset, null, 4));
response.write(JSON.stringify(recordset, null, 4));
}
response.end();
console.log();
});
}
http.createServer(onRequest).listen(8888);
console.log("Server has started!");
}
I use "HttpRequester" to post a request, and add attachment within in (small file) or use the content textbox to send data in it. In my server I get the request but no access to it's body. I tried:
console.log(request.body);
But it's undefined.
I tried to print all request to look for my data, but it's too long and I can't see all the request.
I tried other request because I thought "HttpRequester" may not send me the right request by a friend who sent it to me from the client.
How can I access the body of the request?
If you need to use the default http module you need to read the request body from the data stream:
if (request.method == 'POST') {
request.on('data', function(chunk) {
console.log("Received body data:");
console.log(chunk.toString());
});
}
I would recommend you to have a look at expressjs, it already features routing and has various body parser's for files/json etc.
How can we stop the remaining response from a server -
For eg.
http.get(requestOptions, function(response){
//Log the file size;
console.log('File Size:', response.headers['content-length']);
// Some code to download the remaining part of the response?
}).on('error', onError);
I just want to log the file size and not waste my bandwidth in downloading the remaining file. Does nodejs automatically handles this or do I have to write some special code for it?
If you just want fetch the size of the file, it is best to use HTTP HEAD, which returns only the response headers from the server without the body.
You can make a HEAD request in Node.js like this:
var http = require("http"),
// make the request over HTTP HEAD
// which will only return the headers
requestOpts = {
host: "www.google.com",
port: 80,
path: "/images/srpr/logo4w.png",
method: "HEAD"
};
var request = http.request(requestOpts, function (response) {
console.log("Response headers:", response.headers);
console.log("File size:", response.headers["content-length"]);
});
request.on("error", function (err) {
console.log(err);
});
// send the request
request.end();
EDIT:
I realized that I didn't really answer your question, which is essentially "How do I terminate a request early in Node.js?". You can terminate any request in the middle of processing by calling response.destroy():
var request = http.get("http://www.google.com/images/srpr/logo4w.png", function (response) {
console.log("Response headers:", response.headers);
// terminate request early by calling destroy()
// this should only fire the data event only once before terminating
response.destroy();
response.on("data", function (chunk) {
console.log("received data chunk:", chunk);
});
});
You can test this by commenting out the the destroy() call and observing that in a full request two chunks are returned. Like mentioned elsewhere, however, it is more efficient to simply use HTTP HEAD.
You need to perform a HEAD request instead of a get
Taken from this answer
var http = require('http');
var options = {
method: 'HEAD',
host: 'stackoverflow.com',
port: 80,
path: '/'
};
var req = http.request(options, function(res) {
console.log(JSON.stringify(res.headers));
var fileSize = res.headers['content-length']
console.log(fileSize)
}
);
req.end();