Meteor HTTP.POST call on same machine (for testing) - http

I have created a server side route (using iron-router). Code is as follows :
Router.route( "/apiCall/:username", function(){
var id = this.params.username;
},{ where: "server" } )
.post( function(req, res) {
// If a POST request is made, create the user's profile.
//check for legit request
console.log('post detected')
var userId = Meteor.users.findOne({username : id})._id;
})
.delete( function() {
// If a DELETE request is made, delete the user's profile.
});
This app is running on port 3000 on my local. Now I have created another dummy app running on port 5000. Frrom the dummy app, I am firing a http.post request and then listening it on the app on 3000 port. I fire the http.post request via dummy app using the below code :
apiTest : function(){
console.log('apiTest called')
HTTP.post("http://192.168.1.5:3000/apiCall/testUser", {
data: [
{
"name" : "test"
}
]
}, function (err, res) {
if(!err)
console.log("succesfully posted"); // 4
else
console.log('err',err)
});
return true;
}
But I get the following error on the callback :
err { [Error: socket hang up] code: 'ECONNRESET' }
Not able to figure out whats the problem here.
The server side route is successfully called, but the .post() method is not being entered.
Using meteor version 1.6
192.168.1.5 is my ip addr

Okay so if I use Router.map function, the issue is resolved.
Router.map(function () {
this.route("apiRoute", {path: "/apiCall/:username",
where: "server",
action: function(){
// console.log('------------------------------');
// console.log('apiRoute');
// console.log((this.params));
// console.log(this.request.body);
var id = this.params.username;
this.response.writeHead(200, {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
});
if (this.request.method == 'POST') {
// console.log('POST');
var user = Meteor.users.findOne({username : id});
// console.log(user)
if(!user){
return 'no user found'
}
else{
var userId = user._id;
}
}
});
});

It looks like the content type is not set the application/json. So you should do that...
Setting the "Content-Type" header in HTTP.call on client side in Meteor

Related

Meteorhack:Cluster subscription call failure

I have an UI app on port 8001 and an app named contract on port 7001. I have 'cluster' installed and working. I have a subscription and insert method defined in 'contract' app.
'contract' server/app.js
Cluster.connect("mongodb://<username>:<passwd>#URL");
var options = {
endpoint: "http://localhost:7001",
balancer: "http://localhost:7001", // optional
uiService: "web" // (optional) read to the end for more info
};
Cluster.register("contracts", options);
var Contracts = new Meteor.Collection('contracts');
Meteor.methods({
addContract: addContract,
findContracts: findContracts
});
Meteor.publish("getContracts", function () {
return Contracts.find({});
});
function addContract(c){
var data = {
id: c.id,
type: c.type
};
Contracts.insert(data);
}
function findContracts(){
var contracts = Contracts.find().fetch();
return contracts;
}
I am accessing the methods from an angular controller in my UI app.
UI app server/app.js
Cluster.connect(mongodb://<username>:<passwd>#URL");
var options = {
endpoint: "http://localhost:8001",
balancer: "http://localhost:8001" // optional
//uiService: "web" // (optional) read to the end for more info
};
Cluster.register("web", options);
Cluster.allowPublicAccess("contracts");
UI app controller code
var contractConn = Cluster.discoverConnection('contracts');
contractConn.subscribe('getContracts');
var SubscribedContracts = new Mongo.Collection('SubscribedContracts', {connection: contractConn});
console.log('status', contractConn.status());
vm.contracts = SubscribedContracts.find({}).count();
contractConn.call("findContracts", function(err, result) {
if(err) {
throw err ;
}
else {
console.log(result);
}
});
This is what is happening:
* I can access methods on the contract server
* I can insert or find contracts using these methods
* My subscription is not working. fetch on the cursor shows 0 and count shows 0
* Status on the connection shows 'connecting'
What am I doing wrong with my subscription?
Sudi
I had to change the name of the client mongo collection to the same name as the name of the collection on the service.

Webhook for Mailgun POST?

I am trying to store email messages as JSON (as parsed by Mailgun) in a Mongo.Collection through a Mailgun webhook. I set up an iron-router server-side route to handle the request, but this.request.body is empty. I am using Mailgun's "Send A Sample POST" to send the request, and the POST looks fine using e.g. http://requestb.in/. I was hoping that request.body would have the data, as mentioned in How do I access HTTP POST data from meteor?. What am I doing wrong?
Router.map(function () {
this.route('insertMessage', {
where: 'server',
path: '/api/insert/message',
action: function() {
var req = this.request;
var res = this.response;
console.log(req.body);
...
I'm not sure that is the right syntax. Have you tried using Router.route ?
Router.route('insertMessage',
function () {
// NodeJS request object
var request = this.request;
// NodeJS response object
var response = this.response;
console.log("========= request: =============");
console.log(request);
// EDIT: also check out this.params object
console.log("========= this.params: =============");
console.log(this.params);
// EDIT 2: close the response. oops.
return response.end();
},
{
where: 'server',
path: '/api/insert/message'
}
);
I think the issue is that Mailgun sends a multipart POST request, e.g. it sends "fields" as well as "files" (i.e. attachments) and iron-router does not set up a body parser for multipart requests. This issue is discussed here and here on iron-router's Github Issues. I found this comment particularly helpful, and now I can parse Mailgun's sample POST properly.
To get this working, in a new Meteor project, I did
$ meteor add iron:router
$ meteor add meteorhacks:npm
In a root-level packages.json I have
{
"busboy": "0.2.9"
}
which, using the meteorhacks:npm package, makes the "busboy" npm package available for use on the server via Meteor.npmRequire.
Finally, in a server/rest-api.js I have
Router.route('/restful', {where: 'server'})
.post(function () {
var msg = this.request.body;
console.log(msg);
console.log(_.keys(msg));
this.response.end('post request\n');
});
var Busboy = Meteor.npmRequire("Busboy");
Router.onBeforeAction(function (req, res, next) {
if (req.method === "POST") {
var body = {}; // Store body fields and then pass them to request.
var busboy = new Busboy({ headers: req.headers });
busboy.on("field", function(fieldname, value) {
body[fieldname] = value;
});
busboy.on("finish", function () {
// Done parsing form
req.body = body;
next();
});
req.pipe(busboy);
}
});
In this way I can ignore files (i.e., I don't have a busboy.on("file" part) and have a this.request.body available in my routes that has all the POST fields as JSON.

Angular async data checking issue

My service looks like
//this mthod under myService
this.checkCookie = this.getAuthorization = function() {
return $http({
method: 'GET',
url: '/api/auth'
});
}
And in my route configuration I am doing like
MyAPP.config(function($routeProvider) {
$routeProvider.
when('/', {
controller: check
}).
when('/login', {
templateUrl: '/partials/login.html',
controller: check
}).
when('/products', {
templateUrl: '/partials/products.html'
})
});
var check = function($location, myService, $q) {
if (myService.checkCookie()) {
$location.path("/products");
} else {
$location.path("/login");
}
};
with get request I want to check session data generated by the server is valid or not. And browser will send the cookie information while sending 'GET' in '/api/auth'.
The problem is when I am calling this.checkCookie I am not getting the response syncronoulsy as angular returns response in asnyc fashion. Depending on the checkCookie response I am suppose to redirect to '/products' but I cant do that now.
How can I do that? What I need to change to get this.checkCookie and check whether the response status is 200 or 500?
You can't do synchronous requests with $http. To handle the promise return by the request, you can do this:
var check = function($location, myService, $q) {
myService.checkCookie()
.success(function() {
$location.path("/products");
})
.error(function() {
$location.path("/login");
})
};
You have to call then on the promise that's returned from $http:
myService.checkCookie().then(function () {
$location.path("/products");
}, function () {
$location.path("/login");
});
The first function is the success handler, and the second one is the error (reject) handler.

How to listen to node http-proxy traffic?

I am using node-http-proxy. However, in addition to relaying HTTP requests, I also need to listen to the incoming and outgoing data.
Intercepting the response data is where I'm struggling. Node's ServerResponse object (and more generically the WritableStream interface) doesn't broadcast a 'data' event. http-proxy seems to create it's own internal request, which produces a ClientResponse object (which does broadcast the 'data' event) however this object is not exposed publically outside the proxy.
Any ideas how to solve this without monkey-patching node-http-proxy or creating a wrapper around the response object?
Related issue in issues of node-http-proxy on Github seems to imply this is not possible. For future attempts by others, here is how I hacked the issue:
you'll quickly find out that the proxy is only calling writeHead(), write() and end() methods of the res object
since res is already an EventEmitter, you can start emitting new custom events
listen for these new events to assemble the response data and then use it
var eventifyResponse = function(res) {
var methods = ['writeHead', 'write', 'end'];
methods.forEach(function(method){
var oldMethod = res[method]; // remember original method
res[method] = function() { // replace with a wrapper
oldMethod.apply(this, arguments); // call original method
arguments = Array.prototype.slice.call(arguments, 0);
arguments.unshift("method_" + method);
this.emit.apply(this, arguments); // broadcast the event
};
});
};
res = eventifyResponse(res), outputData = '';
res.on('method_writeHead', function(statusCode, headers) { saveHeaders(); });
res.on('method_write', function(data) { outputData += data; });
res.on('method_end', function(data) { use_data(outputData + data); });
proxy.proxyRequest(req, res, options)
This is a simple proxy server sniffing the traffic and writing it to console:
var http = require('http'),
httpProxy = require('http-proxy');
//
// Create a proxy server with custom application logic
//
var proxy = httpProxy.createProxyServer({});
// assign events
proxy.on('proxyRes', function (proxyRes, req, res) {
// collect response data
var proxyResData='';
proxyRes.on('data', function (chunk) {
proxyResData +=chunk;
});
proxyRes.on('end',function () {
var snifferData =
{
request:{
data:req.body,
headers:req.headers,
url:req.url,
method:req.method},
response:{
data:proxyResData,
headers:proxyRes.headers,
statusCode:proxyRes.statusCode}
};
console.log(snifferData);
});
// console.log('RAW Response from the target', JSON.stringify(proxyRes.headers, true, 2));
});
proxy.on('proxyReq', function(proxyReq, req, res, options) {
// collect request data
req.body='';
req.on('data', function (chunk) {
req.body +=chunk;
});
req.on('end', function () {
});
});
proxy.on('error',
function(err)
{
console.error(err);
});
// run the proxy server
var server = http.createServer(function(req, res) {
// every time a request comes proxy it:
proxy.web(req, res, {
target: 'http://localhost:4444'
});
});
console.log("listening on port 5556")
server.listen(5556);
I tried your hack but it didn't work for me. My use case is simple: I want to log the in- and outgoing traffic from an Android app to our staging server which is secured by basic auth.
https://github.com/greim/hoxy/
was the solution for me. My node-http-proxy always returned 500 (while the direct request to stage did not). Maybe the authorization headers would not be forwarded correctly or whatever.
Hoxy worked fine right from the start.
npm install hoxy [-g]
hoxy --port=<local-port> --stage=<your stage host>:<port>
As rules for logging I specified:
request: $aurl.log()
request: #log-headers()
request: $method.log()
request: $request-body.log()
response: $url.log()
response: $status-code.log()
response: $response-body.log()
Beware, this prints any binary content.

Express / NodeJS Can't send headers after they are sent caused by http requests

First time working with NodeJS (yes, it's awesome) and also using Express as well. Got the web app / service working great but I run in to problems when trying to make more than one http request. Here's a video of how the app causes 2 http requests - http://screencast.com/t/yFKdIajs0XD - as you can see I click on 'articles' it loads an rss feed, then click videos and it loads a youtube feed - both work just fine but after the second call is made it throws an exception. I get the following when I attempt two separate http requests using node's http module:
http.js:527
throw new Error("Can't set headers after they are sent.");
^
Error: Can't set headers after they are sent.
at ServerResponse.<anonymous> (http.js:527:11)
at ServerResponse.setHeader (/Users/rickblalock/node/auti_node/node_modules/express/node_modules/connect/lib/patch.js:47:22)
at /Users/rickblalock/node/auti_node/node_modules/express/node_modules/connect/lib/middleware/errorHandler.js:72:19
at [object Object].<anonymous> (fs.js:107:5)
at [object Object].emit (events.js:61:17)
at afterRead (fs.js:878:12)
at wrapper (fs.js:245:17)
Sample code provided here:
Using my controller module to render the request - http://pastie.org/2317698
One of the tabs (article tab) - the video code is identical minus referencing a video feed: http://pastie.org/2317731
try using the "end" event not "data" like this:
var data = "";
app.get('/', function(req, res){
var options = {
host: 'http://www.engadget.com',
path: '/rss.xml',
method: 'GET'
};
if (data === "") {
var myReq = http.request(options, function(myRes) {
myRes.setEncoding('utf8');
myRes.on('data', function(chunk) {
console.log("request on data ");
data += chunk;
});
myRes.on('end', function () {
console.log("request on END");
res.render('index', {
title: 'Express',
data: data
});
});
});
myReq.write('data\n');
myReq.end();
}
else {
res.render('index', {
title: 'Express',
data: data
});
}
});
old answer
i also think that this is the culprit:
var req = http.request(options, function(res) {
res.setEncoding('utf8');
res.on('data', function(chunk) {
parseArticle(chunk);
});
});
req.write('data\n');
req.end();
the first line is async so everything inside the callback is called after you do req.write() and req.end()
put these two lines into the callback.

Resources