Issues with nodejs' request and pipe - node.js

I'm having an issue with the following code. I'm trying to make a POST request (json) to a URL using pipe but I get the error "write after end" - Internal Server Error. Can someone please help?
test: function( req, res, next) {
var requesty = request.post({
url: dataUrl,
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(body)
});
req.pipe(requesty).on('error', function (error) {
logger.withRequestLog(res, 'error', 'CC Melville Proxy failed!', {
assetUrl: dataUrl,
error: error,
});
next(error);
}).pipe(res);
}

You are getting error because of body: JSON.stringify(body). You can't (also don't need) to pass body as when you are piping raw bytes are being piped as well. Also This middleware should be FIRST as you don't want to use bodyParser etc which will read the stream and make it empty.
Below is an working example where I am proxying my request to one my routes(It can be external also):
const express = require('express');
const app = express();
const request = require('request');
const bodyParser = require('body-parser').json();
const dataUrl = '/employees'
app.use(dataUrl, bodyParser, (req, res)=>{
res.json({
body: req.body || {},
method: req.method,
param: req.params,
headers: req.headers,
url: req.url
});
})
app.use('/', (req, res) => {
var requesty = request({
url: 'http://localhost:8080'+dataUrl,
headers: {
'Content-Type': 'application/json'
},
})
req.pipe(requesty).on('error', function (error) {
console.log('error', 'CC Melville Proxy failed!', {
assetUrl: dataUrl,
error: error,
});
}).pipe(res);
});
app.listen(8080, () => {
console.log('started');
})
Note: You don't need to specify method as it will automatically be passed. From the doc:
You can also pipe() from http.ServerRequest instances, as well as to
http.ServerResponse instances. The HTTP method, headers, and
entity-body data will be sent.

Related

Why data not getting posted to the route?

I have an application wherein after getting the data from user, I am posting it to the /create
route.
However upon making a post request, it gives me error:
POST http://localhost:5000/create 404 (Not Found)
The code for making post request:
submitbtn.addEventListener('click', (e) => {
e.preventDefault();
const data=validateForm();
if (data) {
postData(data);
console.log("submitted");
}
})
async function postData(data) {
await fetch('http://localhost:5000/create', {
method: 'POST',
body: {
title: `${data.title}`, content: `${data.text}`
},
headers: {
'Content-Type': 'application/json'
}
})
}
Handling the post request on my server:
const express=require('express');
const app= express();
const router=express.Router();
const News=require('./news/news');
app.use(express.static('./public'));
router.post('/create',(req,res)=>{
res.send("Successful");
})
app.listen(5000,()=>{
console.log("Server listening on 5000 port");
})

Node.js: Access JSON body of HTTP POST request with express

I'm making an http post request to my express web server sending dummy data as json. It correctly receives the request and can send back a json object, but for some reason it can't manage to access the post request body.
I'm using this code for express:
const express = require('express');
const app = express();
const port = 3000;
app.post('/test', (req, res) => {
console.log(req.body);
res.json({"some": "thing"});
});
app.listen(port, () => {
console.log(`Listening at http://localhost:${port}`)
});
And this is the code of the request:
const req = http.request({
hostname: '127.0.0.1',
port: 3000,
path: '/test',
method: 'POST',
json: {
url: "https://www.nothing.com",
name: "hello"
}
}, res => {
console.log(`statusCode: ${res.statusCode}`)
res.on('data', d => {
process.stdout.write(d)
})
})
req.on('error', error => {
console.error(error)
})
req.end()
As you can see I'm running this locally. The client receives a status code 200 and the json {"some": "thing"} sent by the server, but the server gets "undefined" from req.body. I tried using:
headers: {
'Content-Type': 'application/json'
}
body: JSON.stringify({
url: "https://www.nothing.com",
name: "hello"
})
instead of json directly in the request options, but to no avail. I even tried using app.use(express.json()); as someone suggested.
What is the problem?
Apparently the way I was doing the post request was not correct, I had to send the body in a separate line with req.write(), like this:
const http = require('http');
const data = JSON.stringify({ //<--- data to send as body
url: "https://www.nothing.com",
name: "hello"
});
const req = http.request({
hostname: '127.0.0.1',
port: 3000,
path: '/test',
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
}, res => {
console.log(`statusCode: ${res.statusCode}`);
res.on('data', d => {
process.stdout.write(d);
})
})
req.on('error', error => {
console.error(error);
})
req.write(data); //<--- this line
req.end();
You have to add body-parser middleware http://expressjs.com/en/resources/middleware/body-parser.html
req.body empty on posts

Cross-Origin Request Blocked even after adding headers in server code

I've a simple API in Express/Node and I also have a simple angular application for posting blogs. The only problem is when I hit the /contribute route using POST method. I'm getting this error on both chrome and firefox:
error: error { target: XMLHttpRequest, isTrusted: true, lengthComputable: false, … }
​
headers: Object { normalizedNames: Map(0), lazyUpdate: null, headers: Map(0) }
​
message: "Http failure response for localhost:3000/api/contribute: 0 Unknown Error"
​
name: "HttpErrorResponse"
​
ok: false
​
status: 0
​
statusText: "Unknown Error"
​
url: "localhost:3000/api/contribute"
​
: {…}
​​
constructor: class HttpErrorResponse { constructor(init) }​​
: {…}
​​​
constructor: class HttpResponseBase { constructor(init, defaultStatus, defaultStatusText) }​​​
: {…
Here's my server side code.
api.js
...
router.post('/contribute', (req, res) => {
console.log('Pushing new article');
let userPost = req.body;
let post = new Post(userPost);
post.save((error, registeredPost) => {
if (error) {
console.log(error);
} else {
res.status(200).send(registeredPost);
}
})
})
...
module.exports = router;
server.js
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const api = require('./routes/api');
const cors = require('cors');
app.use(bodyParser.json());
// app.use(cors({ origin: 'http://localhost:4200' })); <--- TRIED THIS ALSO
app.use(function (req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:4200');
// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', true);
// Pass to next layer of middleware
next();
});
app.use('/api', api);
app.get('/', function(req, res) {
res.send('Server is up and running!');
})
app.listen(3000, function() {
console.log('Server listening port:3000');
});
Yes, server is up and running.
Here is angular code.
auth.service.ts
private _contributeUrl = "https://localhost:3000/api/contribute";
...
pushNewPost(newPost) {
console.log("here is the new post", newPost); // GETTING CORRECT OUTPUT
return this._http.post<any>(this._contributeUrl, newPost);
}
contribute.component.ts
this._auth.pushNewPost(this.makeNewPost)
.subscribe (
res => {
(<HTMLInputElement>document.getElementById("inputTitle")).value="";
this.editorForm.reset();
this.addSingle();
},
err => console.log(err)
);
Now the fun part is that the same code is working perfectly when I make a post request to this route using Postman without any error.
Please correct my mistake. After adding:
pushNewPost(newPost) {
console.log("here is the new post", newPost);
let headers = new HttpHeaders({
'Content-Type': 'application/json',
});
let options = { headers: headers };
return this._http.post<any>(this._contributeUrl, newPost);
}
I'm getting this:
Seems like you are not sending in the headers from angular. Make the following changes:
pushNewPost(newPost) {
// adding the headers
const headers = new HttpHeaders({
'Content-Type': 'application/json',
});
const options = { headers: headers };
return this._http.post<any>(this._contributeUrl, newPost, options);
}

issue with react ui communicating with node

This is the react fetch:
var json = {
json: JSON.stringify({
a: 1,
b: 2
}),
delay: 3
};
fetch('/saveInfo', {
method: 'post',
headers: {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json'
},
body: JSON.stringify(json.json)
})
.then(function (response) {
return response.json();
})
.then(function (result) {
alert(result);
console.log("The file was saved!");
})
.catch (function (error) {
console.log('Request failed');
});
This is node:
<pre>
var express = require('express');
module.exports = function(app) {
var router = express.Router();
router.get('/', function (req, res) {
console.log('from node');
console.log(req);
res.json({status: 'UP'});
});
app.use("/saveInfo", router);
}
</pre>
The code above doesn't work with the 2nd parameter to the fetch.
But when I execute it w/o the second parameter to fetch as below:
fetch('/saveInfo')
.then(function (response) {
return response.json();
})
.then(function (result) {
alert(result);
console.log("The file was saved!");
})
.catch (function (error) {
console.log('Request failed');
});
Works fine and is able to communicate to the node program.
Can any one help me with this what is wrong. I wanted to send the react's UI forms state t the node program.
You need to add a handler for the POST requests also.
In the fetch method for 1st case, you have given the method type as POST but node doesn't have any handling for that.
However, when you don't give the second parameter, it is considered as GET request and is intercepted by router.get.
Just add this in the node (before app.use line):
router.post("/", function (req, res) {
console.log('from node');
console.log(req);
res.json({status: 'UP'});
});
It will enable node to listen for POST requests.
Edit: To have access to post request body params in router.post, you need body-parser package. Install this package and add these two lines before initializing the express router:
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: false }))
Read http://jilles.me/express-routing-the-beginners-guide/ for detailed explanation

reCAPTCHA with node.js and express

Building an app with node.js and express and want to implement reCAPTCHA.
My code is the following:
const app = require('express')();
const bodyParser = require('body-parser');
var request = require('request-promise');
app.use(bodyParser.urlencoded({ extended: false }))
app.post('/jow', (req, res, next) => {
console.log(req.body['g-recaptcha-response']);
var options = {
method: 'POST',
uri: 'https://www.google.com/recaptcha/api/siteverify',
body: {
secret: '6LcAuUoUAAAAAH-uiWl9cz0Wicg7iUsDxHImrgLO',
response: req.body['g-recaptcha-response'],
},
json: true // Automatically stringifies the body to JSON
};
request(options)
.then((response) => {
console.log(response);
})
.catch((err) => {
console.log('error');
})
});
I get the following output when I verify the CAPTCHA and send the form:
The errors state that I have a missing input response (while I have the token as we can see logged out) and a missing input secret. This indicates that something went wrong in the http request send using the request-promise package. What am I doing wrong here?
I know it's been a long time since the question, but, for future references, here's the solution.
The problem is with the body key:
body: {
secret: RECAPTCHA_SECRET,
response: req.body['g-recaptcha-response']
},
When using request-promise module and recaptcha, you should use the form key instead.
form: {
secret: RECAPTCHA_SECRET,
response: req.body['g-recaptcha-response']
},
Reference: https://github.com/request/request-promise#post-like-html-forms-do

Resources