I am using node-http-proxy for the POST request as follows:
route.js
---------
var express = require('express');
var httpProxy = require('http-proxy');
var bodyParser = require('body-parser');
var proxy = httpProxy.createProxyServer({secure:false});
var jsonParser = bodyParser.json();
proxy.on('proxyReq', function(proxyReq, req, res, options) {
logger.debug("proxying for",req.url);
//set headers
logger.debug('proxy request forwarded succesfully');
});
proxy.on('error', function (err, req, res) {
res.writeHead(500, {
'Content-Type': 'text/plain'
});
res.end('Something went wrong. And we are reporting a custom error message.');
});
proxy.on('proxyRes', function (proxyRes, req, res) {
console.log('RAW Response from the target', JSON.stringify(proxyRes.headers, true, 2));
});
module.exports = function(app){
app.post('/recording',jsonParser,function(req,res){
// update request body
proxy.web(req, res, { target: <<host>>:<<port>>});
});
}
app.js
---------
var express = require('express');
var app = express();
require('./routes')(app);
app.listen(8080);
console.log("Demo server running");
I also use bodyparser middleware and it has a known issue as mentioned in Gitbug issue. So I tried adding this line as the last line in app.js
app.use(require('connect-restreamer')());
But still the POST request hangs and ultimately fails. How do I fix this ? Is there any alternatives for bodyparser ?
Try reversing the order of the bodyParser- and proxy middleware:
module.exports = function(app){
app.post('/recording', function(req,res){
// update request body
proxy.web(req, res, { target: <<host>>:<<port>>});
}, jsonParser);
}
Think this issue is similar to: socket hang up error with nodejs.
To expand on this a bit, what's happening here is that the node request is a stream, it can only be read once, after that the stream data is consumed.
When you use body-parser middleware in express, it will consume the request stream body - if you try to proxy the request after this, there's no body stream to send, so the other end of the proxy receives a POST with a content-length, etc... but waits indefinitely to receive the POST body which never arrives.
If you want to proxy POST/PUT or really any requests that contain a body, you have to do that before any middleware consumes the body. That's why #chimmurai answer above works.
Also, be aware that for the same reason, middleware that executes after you proxy a request will be affected the same way, once the request stream is consumed there won't be anything for subsequent middleware to read. That's the reason for things like connect-restreamer.
Related
I want to create a request GET that returns a json data type with ajax
The route is so simply like this:
app.get('/', function(req, res) {
res.json({ answer: 42})
});
When I open / in the browser it render this:
All ok, but I trying to get answer json with XMLHttpRequest vanilla JS (no jquery):
var xhr = new XMLHttpRequest();
xhr.open("GET", 'http://localhost:3000/');
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.responseType = 'json'
xhr.addEventListener('load', function () {
alert(this.response) // response is 'null'
})
xhr.send();
the response property is null and thw browser look like this:
I get nothing back. What am I missing here?
I don't see any issue with the code It must be a cross domain issue. The reason it works from postman is it handle the preflight automatically. You need to enable cors in your express server like this.
const express = require('express')
const app = express();
var cors = require('cors')
app.use(cors())
app.get('/', function(req, res) {
res.json({ answer: 42})
});
app.listen(3000, () => {
console.log("listening");
});
Hope it helps.
I am submitting a form and the following gets called...
handleLogin(){
fetch('http://localhost:8080', {
method: 'post',
body: JSON.stringify({
username: this.state.username,
password: this.state.password
})
});
}
It makes a POST request to my restAPI. The request works, but the data is not passed...
app.post('/', function(req, res, next) {
console.log(req.body.username);
....
This prints out undefined, meaning password and username are not passed through the call. What am I doing wrong?
Express by default doesn't parse the body of the request. In order to enable parsing, you will need to use a middleware such as body-parser. You can find some information in the express docs.
Also, the client side needs to indicate that it's sending json data. That can be achieved with the Content-Type header. There is a pretty good tutorial about fetch() here. You can jump directly to the Request Headers section which is relevant for your question.
var express = require("express");
var app = express();
var bodyParser = require('body-parser');
const PORT = process.env.PORT || 7070;
const BASEURL = process.env.BASEURL || 'http://localhost/7070';
app.use(bodyParser.urlencoded({extended:true}));
app.listen(PORT, function() { console.log('Server running on'+BASEURL);
});
In my scenario I need forward get request to another end point. In my machine there are two servers php and node.js server. Node.js is like a "man in the middle", PHP server must work in the same way.
Node.js server code
var express = require('express');
var fs = require('fs');
var path = require('path');
var http = require('http');
var https = require('https');
var app = express();
var HTTP_PORT = 3000;
// Create an HTTP service
http.createServer(app).listen(HTTP_PORT,function() {
console.log('Listening HTTP on port ' + HTTP_PORT);
});
//endpoint for tracking
app.get('/track', function(req, res) {
sendRequestToOtherEndPoint(req);
processRequest(req);
res.setHeader('Content-Type', 'application/json');
res.send('Req OK');
});
function processRequest(req){
console.log("request processed");
}
function sendRequestToOtherEndPoint(req){
//magic here :)
}
When this server receive a get request in port 3000, it process request information and it must forward the same requesto to another end point.
For example:
Get localhost:3000/track?param1=1¶m2=2
Server process get request
Server forward get request to localhost/final-endpoint?param1=1¶m2=2
Depending on what you're trying to do, you can create a new request to the end-point:
//endpoint for tracking
app.get('/track', function(req, res) {
req.get({url: 'http://end-point', headers: req.headers});
processRequest(req);
res.setHeader('Content-Type', 'application/json');
res.send('Req OK');
});
More info: https://github.com/request/request
There are a couple of useful libraries that one could use:
http-proxy-middleware:
const proxy = require('http-proxy-middleware')
var apiProxy = proxy('/track', {target: 'http://end-point'});
app.use(apiProxy)
axios-express-proxy
import express from 'express';
import { Proxy } from 'axios-express-proxy';
const app = express();
const port = 3000;
app.get('/track', (req, res) => Proxy('http://end-point', req, res));
In you case res.redirect might help.
app.get('/track', function(req, res) {
// process the request
// then redirect
res.redirect('/final-endpoint');
});
Then catch the redirected request in final endpont.
app.get('/final-endpoint', function(req, res) {
// proceess redirected request here.
});
See the Express docs
If your second endpoint is on a different server, (e.g. PHP) then you're going to need to either redirect the client (as in sohel's answer), or spoof a request from Node to the PHP server and then send the response back to the client. This latter option is definitely non-trivial so I would question whether it's crucial not to use a client redirect.
If you're talking about two express endpoints, then I think the simplest answer might be not to actually forward at all, but just use the endpoint callback directly instead:
app.get('/track', trackCallback);
app.get('/otherendpoint', otherendpointCallback);
function otherendpointCallback(req, res) {
// do your thing
}
function trackCallback(req, res) {
otherendpointCallback(req, res);
processRequest(req);
res.setHeader('Content-Type', 'application/json');
res.send('Req OK');
};
Depending on exactly what you want to do at the other end point, you might need to spoof some of req's fields (e.g. req.url)
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.
I use request to implement the following reverse proxy to CouchDB in Express:
app.all(/^\/db(.*)$/, function(req, res){
var db_url = "http://localhost:5984/db" + req.params[0];
req.pipe(request({
uri: db_url,
method: req.method
})).pipe(res);
});
When making GET requests, it works: requests go from the client to node.js to CouchDB and back again successfully. POST and PUT requests hang indefinitely. Log statements run until the proxy, but CouchDB doesn't indicate receipt of the request. Why is this happening, and how can it be fixed?
Express' bodyparser middleware modifies the request in a way that causes piping to hang. Not sure why, but you can fix it by making your proxy into middleware that catches before the bodyparser. Like this:
// wherever your db lives
var DATABASE_URL = 'http://localhost:5984/db';
// middleware itself, preceding any parsers
app.use(function(req, res, next){
var proxy_path = req.path.match(/^\/db(.*)$/);
if(proxy_path){
var db_url = DATABASE_URL + proxy_path[1];
req.pipe(request({
uri: db_url,
method: req.method
})).pipe(res);
} else {
next();
}
});
// these blokes mess with the request
app.use(express.bodyParser());
app.use(express.cookieParser());
request makes get requests by default. You need to set the method.
app.all(/^\/db(.*)$/, function(req, res){
var db_url = ["http://localhost:5984/db", req.params[0]].join('/');
req.pipe(request({
url: db_url,
method: url.method
})).pipe(res);
});
(code untested, let me know if it doesn't work, but it should be close)