Proxy Post Request to another server is failing - node.js

I am new to node.js. I have a requirement to proxy a POST request (with payload) to another server from node.js and process its response back to the browser client.
my scenario (browser <-> node.js <-> final destination server).
This is how my code looks, before i explain my issue.
app.post('^*$', function(req, res) {
delete req.headers.host; // i read somewhere to delete the old host
req.headers.host = 'ipadress:port';
request({ url: 'http://ipaddress:port' + req.path, headers: req.headers, body: req.body }, function(err, remoteResponse, remoteBody) {
if (err) { return res.status(500).end('Error no response'); }
res.writeHead(200,{
'Content-Length': remoteBody.length,
'Content-Type': 'text/xml' }); // copy all headers from Response
res.end(remoteBody);
});
});
I keep on getting "500 internal server error" "Error no response".
I strongly suspect (although not sure!) , the reason for this error is my payload from initial request is not being copied to the proxied request and the complete url which my final server expects is not there.
Can someone advise me, how i can copy the url and payload to the forwarding request ?
Also, how do i handle the response back from the forwarding serer ?
My payload is a xml object and final url is
http://ipaddress:port/XISOAPAdapter/MessageServlet?senderParty=&senderService=BS_WSAPPS_Q&receiverParty=&receiverService=&interface=SI_OrderStatusRequest_Out&interfaceNamespace=http://xyz/IF027/EC/OrderStatus/I_WS_APPS
#Krzysztof Sztompka.
Here is the information you asked me to put. miine is a dev environment.
_http_outgoing.js:512
throw new TypeError('first argument must be a string or Buffer');
^
TypeError: first argument must be a string or Buffer
at ServerResponse.OutgoingMessage.end (_http_outgoing.js:512:11)
at Request._callback (D:\MyNode.js\serverproxy.js:18:43)
at self.callback (D:\MyNode.js\node_modules\request\request.js:198:22)
at Request.emit (events.js:107:17)
at Request.onRequestError (D:\MyNode.js\node_modules\request\request.js:867:8)
at ClientRequest.emit (events.js:107:17)
at Socket.socketOnEnd (_http_client.js:300:9)
at Socket.emit (events.js:129:20)
at _stream_readable.js:908:16
at process._tickCallback (node.js:355:11)

Related

Unable to gracefully close http2 client stream in nodejs

I have the following code which has been heavily inspired from nodejs official documentation of a client-side example
import http2 from 'http2';
// The `http2.connect` method creates a new session with example.com
const session = http2.connect('https://somedomain.com');
// Handle errors
session.on('error', (err) => console.error(err))
const req = session.request({
':authority': 'somedomain.com',
':path': '/some-path',
':method': 'GET',
':scheme': 'https',
'accept': 'text/html',
});
// To fetch the response body, we set the encoding
// we want and initialize an empty data string
req.setEncoding('utf8')
let data = ''
// append response data to the data string every time
// we receive new data chunks in the response
req.on('data', (chunk) => { data += chunk })
// Once the response is finished, log the entire data
// that we received
req.on('end', () => {
console.log(`\n${data}`)
session.close();
});
req.on('error', (error) => {
console.log(error);
});
req.end();
Please note that the actual hostname has been replaced with somedomain.com. Running this, results in data getting logged, as expected, however, the process doesn't shut down gracefully. I get the following unhandled error in the terminal.
node:events:504
throw er; // Unhandled 'error' event
^
Error [ERR_HTTP2_STREAM_ERROR]: Stream closed with error code NGHTTP2_FLOW_CONTROL_ERROR
at new NodeError (node:internal/errors:371:5)
at ClientHttp2Stream._destroy (node:internal/http2/core:2330:13)
at _destroy (node:internal/streams/destroy:102:25)
at ClientHttp2Stream.destroy (node:internal/streams/destroy:64:5)
at Http2Stream.onStreamClose (node:internal/http2/core:544:12)
Emitted 'error' event on ClientHttp2Stream instance at:
at emitErrorNT (node:internal/streams/destroy:157:8)
at emitErrorCloseNT (node:internal/streams/destroy:122:3)
at processTicksAndRejections (node:internal/process/task_queues:83:21) {
code: 'ERR_HTTP2_STREAM_ERROR'
}
I understand it is possible that the server is behaving incorrectly. However, there should be a way on the nodejs client to close the session gracefully. Regardless, what would be the ideal way to handle such errors? I've already tried listening to session.on('error') and req.on('error') but that doesn't work.

How to fix grant_type error is NULL - unsupported grant type with Pay Pal's REST API for access token

I'm calling Paypal's REST API to get an access token https://developer.paypal.com/docs/api/overview/#get-an-access-token
I'm using node with superagent to make the AJAX call.
Here is my code:
const basicAuth = Buffer.from(`${PAYPAL_CLIENT}:${PAYPAL_SECRET}`).toString('base64')
request
.post(PAYPAL_OAUTH_API)
.set('Accept', 'application/json')
.set('grant_type', 'client_credentials')
.set('Authorization', `Basic ${basicAuth}`)
.send()
.end((result) => {
console.log(result.response.error)
})
And here is the logs with the errors I'm getting
{ Error: cannot POST /v1/oauth2/token/ (400)
at Response.toError (C:\Users\shlomo\projects\tribewise-backend-v1\node_modules\superagent\lib\node\response.js:94:15)
at ResponseBase._setStatusProperties (C:\Users\shlomo\projects\tribewise-backend-v1\node_modules\superagent\lib\response-base.js:123:16)
at new Response (C:\Users\shlomo\projects\tribewise-backend-v1\node_modules\superagent\lib\node\response.js:41:8)
at Request._emitResponse (C:\Users\shlomo\projects\tribewise-backend-v1\node_modules\superagent\lib\node\index.js:850:20)
at parser (C:\Users\shlomo\projects\tribewise-backend-v1\node_modules\superagent\lib\node\index.js:1036:38)
at IncomingMessage.res.on (C:\Users\shlomo\projects\tribewise-backend-v1\node_modules\superagent\lib\node\parsers\json.js:19:7)
at emitNone (events.js:111:20)
at IncomingMessage.emit (events.js:208:7)
at endReadableNT (_stream_readable.js:1064:12)
at _combinedTickCallback (internal/process/next_tick.js:138:11)
at process._tickDomainCallback (internal/process/next_tick.js:218:9)
status: 400,
text: '{"error":"unsupported_grant_type","error_description":"Grant Type is NULL"}',
method: 'POST',
path: '/v1/oauth2/token/' }
Why am I getting an error unssuported grant type - the grant type is NULL?
In postman it works but I can't get it to work with superagent and node. Paypal gives two examples here with postman and curl. Why is it not working with superagent?
From paypal docs which you've linked to:
If you use a command-line tool other than cURL, set the Accept header to application/x-www-form-urlencoded
From superget docs which you've linked to:
By default sending strings will set the Content-Type to application/x-www-form-urlencoded
So change your request to:
// PAYPAL_LINK = "https://api.sandbox.paypal.com"
// PAYPAL_OAUTH_API = "/v1/oauth2/token"
request(PAYPAL_LINK)
.post(PAYPAL_OAUTH_API)
.send('grant_type=client_credentials')
.auth(PAYPAL_CLIENT, PAYPAL_SECRET)
.then(response => console.log(response))
.catch(error => console.error(error))
Optionally set Accept: application/json if you want response as json

AJAX Post request - sending json object to node.js server

I am making an Ajax Post request:
$.ajax({
type:"POST",
dataType:"json",
contentType: "application/json",
data:newWorkLog,
url:"/add",
})
.done(function(response){
console.log("Response of update: ",response)
})
.fail(function(xhr, textStatus, errorThrown){
console.log("ERROR: ",xhr.responseText)
return xhr.responseText;
});
and was expecting to pass that newWorkLog object to an API method through my node.js server:
var bodyParser = require('body-parser');
app.use(bodyParser.json())
app.post('/add', function(req, res){
console.log(req.body) //This doesnt output anything
res.send(JSON.stringify(req.body));
});
After trying some approaches, I decided to only check what is being sent to my server.
Doing this, the message I get is:
SyntaxError: Unexpected token # in JSON at position 0
at JSON.parse (<anonymous>)
at createStrictSyntaxError (C:\working\app\node_modules\body-parser\lib\types\json.js:157:10)
at parse (C:\working\app\node_modules\body-parser\lib\types\json.js:83:15)
at C:\working\app\node_modules\body-parser\lib\read.js:121:18
at invokeCallback (C:\working\app\node_modules\raw-body\index.js:224:16)
at done (C:\working\app\node_modules\raw-body\index.js:213:7)
at IncomingMessage.onEnd (C:\working\app\node_modules\raw-body\index.js:273:7)
at emitNone (events.js:106:13)
at IncomingMessage.emit (events.js:208:7)
at endReadableNT (_stream_readable.js:1055:12)
at _combinedTickCallback (internal/process/next_tick.js:138:11)
at process._tickCallback (internal/process/next_tick.js:180:9)
When I console.log my newWorkLog object, I can see from my client side, the correct json object.
when I check the param on the console I see the request payload and it looks like:
user%5Bid%5D=109&user%5BuserName%5D=myname
What could be causing that error?
You say newWorkLog is an object so you need to convert it to json to send it in your request.
$.ajax({
type:"POST",
dataType:"json",
contentType: "application/json",
data:JSON.stringify(newWorkLog),
url:"/add",
})
.done(function(response){
console.log("Response of update: ",response)
})
.fail(function(xhr, textStatus, errorThrown){
console.log("ERROR: ",xhr.responseText)
return xhr.responseText;
});

What could cause "connect ETIMEDOUT" error when the URL is working in browser?

I train myslef with NodeJS and tried a simple GET call.
Here is my code:
var http = require('http');
var options = {
host: 'www.boardgamegeek.com',
path: '/xmlapi/boardgame/1?stats=1',
method: 'GET'
}
var request = http.request(options, function (response) {
var str = ""
response.on('data', function (data) {
str += data;
});
response.on('end', function () {
console.log(str);
});
});
request.on('error', function (e) {
console.log('Problem with request: ' + e.message);
});
request.end();
The URL called seems to work in my browser https://www.boardgamegeek.com/xmlapi/boardgame/1?stats=1
Anyway, I've got Problem with request: connect ETIMEDOUT when I run the code and I have no idea how to fix it.
What could cause this error ? Is it my code or is it a network/proxy issue?
When behind a proxy you need to make the following modifications (as explained in this answer):
put the proxy host in the host parameter
put the proxy port in the port parameter
put the full destination URL in the path parameter :
Which gives:
var options = {
host: '<PROXY_HOST>',
port: '<PROXY_PORT>',
path: 'http://www.boardgamegeek.com/xmlapi/boardgame/1?stats=1',
method: 'GET',
headers: {
Host: 'www.boardgamegeek.com'
}
}
In my case it was because of http but not https as required
If this error occurs while using POSTMAN.
So, when you call a request in Postman and the API requires your VPN to be up before you can make a successful call. You will need to connect or reconnect your VPN.
In my case, I was working on a company's laptop. I found out it was the VPN that was down.
The following change with the request worked for me:
var options = {
proxy:'PROXY URL',
uri: 'API URL',
method: 'GET'
}
request(options, function (err, response, body) {
if(err){
console.log('error:', err);
} else {
console.log('body:', body);
}
});
In my case it was a misconfigured subnet. Only one of the 2 subnets in the ELB worked. But my client kept trying to connect to the misconfigured one.
if you have URL
like :
URL: 'localhost:3030/integration',
The URL above cause some issues because HTTP does not exist at the beginning of URL so Just change it to it should work.
URL: 'http://localhost:3030/integration',
In my case, I was getting this error because the request body of my post api was very large.
I was facing this issue on Ubuntu Server while maintaining a node instance on PM2. Basically after restarting the instance after taking the pull I was getting the same error on initial connection of mySQL inside the code.
Error: connect ETIMEDOUT
at Connection._handleConnectTimeout (/home/deam_server/node_modules/mysql/lib/Connection.js:419:13)
at Object.onceWrapper (events.js:275:13)
at Socket.emit (events.js:182:13)
at Socket.EventEmitter.emit (domain.js:442:20)
at Socket._onTimeout (net.js:447:8)
at ontimeout (timers.js:427:11)
at tryOnTimeout (timers.js:289:5)
at listOnTimeout (timers.js:252:5)
at Timer.processTimers (timers.js:212:10)
Though the same code was running perfectly on my local machine.
After that I used "df" command which helped me to realise that my root directory was 100% occupied. I allotted some memory to the root directory and the restarted the node instance and then it started working fine.
Sometimes it can simply be because your internet is down.

Twitter stream api

I am trying to learn and understand nodejs. While trying to connect to api of Twitter stream and track tweets, I get following error :
undefined:1
<html>\n<head>\n<meta http-equiv="Content-Type" content="text/html; charset=ut
^
SyntaxError: Unexpected token <
at Object.parse (native)
at IncomingMessage.<anonymous> (/home/ytsejam/public_html/nodejs/11/twitter.js:15:20)
at IncomingMessage.emit (events.js:95:17)
at IncomingMessage.<anonymous> (_stream_readable.js:764:14)
at IncomingMessage.emit (events.js:92:17)
at emitReadable_ (_stream_readable.js:426:10)
at emitReadable (_stream_readable.js:422:5)
at readableAddChunk (_stream_readable.js:165:9)
at IncomingMessage.Readable.push (_stream_readable.js:127:10)
at HTTPParser.parserOnBody [as onBody] (http.js:142:22)
here is my code which I try to connect :
var https = require("https");
var options = {
host: 'stream.twitter.com',
path: '/1.1/statuses/filter.json?track=bieber',
method: 'GET',
headers: {
"Authorization": "Basic " + new Buffer("username:password").toString("base64")
}
};
var request = https.request('https://stream.twitter.com/1.1/statuses/filter.json?track=query', function(response){
var body = '';
response.on("data", function(chunk){
var chunk = chunk.toString();
try {
var tweet = JSON.parse(chunk);
} catch (err) {
console.log("JSON parse error:" + err);
}
console.log(tweet.text);
});
response.on("end",function(){
console.log("Disconnected");
});
});
request.end();
I did a research and tried to debug. my best guess is var tweet = JSON.parse(chunk); may cause problems. second option, I am missing oauth parameters.
Can you help me ? Thanks.
Edit :
I solved this using answer here Node.js and Twitter API 1.1
JSON.parse() is throwing a SyntaxError because the data it is trying to parse is HTML and not JSON.
In general, it's a good idea to wrap JSON.parse() in a try/catch block so you can handle those sorts of things gracefully.
(It is possible that there is a problem in your oauth stuff and it is failing to authenticate. So instead of getting JSON, you are getting an HTML page telling you that authentication has failed. But that is just a guess.)

Resources