How to handle a C# ByteArrayContent in NodeJS - node.js

I have a simple C# web api service that returns a pdf document as bytearraycontent in the response of an IHttpActionResult. I can easily handle this as a blob on the client (js in browser) and set it as a the src of an iframe. Everything displays correctly.
Due to some changes in requirements, I'm now implementing a simple appserver in nodejs using express; this will serve as a proxy server. From my client, I'm able to make the call to this express server, which in turn calls my C# service. I get 200 http OK status code, but seem to not be able to the handle pdf byte array in node. I tried Buffer methods, readstreams etc... Nothing worked.
Can you guys throw some light on this? Below is the code:-
httpRequester.get(`${constants.serviceTarget}/api/DocGen/Download/Id/true`, (error, response, body) => {
if(error) {
console.log(error)
} else {
console.log(Buffer.isBuffer(body)) // this is always false
const stream = streamifier.createReadStream(response.body)
console.log("Created stream")
res.setHeader("Access-Control-Allow-Origin", "*")
res.setHeader("Content-Type", "application/pdf");
res.setHeader("Content-Disposition", "inline; filename=document.pdf");
res.writeHead(response.statusCode)
stream.pipe(res)
console.log("Sent stream to response")
console.log("***********************************")
}
})

So turns out I was doing too much here. Since I'm using nodejs request module to make the GET call, all I need to then do is pipe the response to the client; like below:-
httpRequester.get(`${constants.serviceTarget}/api/Pandadoc/DownloadDocument/${opportunityId}/true`, (error, response, body) => {
if(error) {
console.log(error)
}
}).pipe(res)
I got the idea from: https://github.com/expressjs/express/issues/2910

Related

ERR_HTTP_HEADERS_SENT caused by response to POST request after refresh node.js Express. res.send inside fs.watch callback

On my webpage user can enter text and press send. this causes the server to append the message to a json object stored in a file. when this file is altered it then sends the new json to the client.
app.post("/recieve",function(req,res){
watcher = fs.watch(__dirname+"/msgs/msg.json", (eventName, filename) => {
watcher.close();
fs.readFile(__dirname+"/msgs/msg.json", (err,data) => {
return res.send(data);
});
});
})
here is the client side
async function recieveMSG(){
$.ajax({
url: "recieve",
type: "POST",
contentType: "text; charset=utf-8"
}).done(function(data){
$("#msgbox").html("<br>"+data+"<br>");
recieveMSG();
});
}
recieveMSG();
As shown in the code above, the client sends a POST request to the server. Next after the json file is changed the server responds to the POST request with the json. I know this may be the completely wrong way to do it, but I want to know why res.send(data) is being called twice on the same res object.
It seems after the first refresh the recieve POST request just doesnot do anything
app.post("/recieve",async function(req,res){
try{
watcher.close();
}
catch(e){
console.log("WatcherUndefined --first execution");
}
watcher = fs.watch(__dirname+"/msgs/msg.json", (eventName, filename) => {
watcher.close();
fs.readFile(__dirname+"/msgs/msg.json", (err,data) => {
return res.send(data);
});
});
})
The problem was that the watcher wasn't getting closed after the client refreshed/disconnected. After the client refreshed the res object generated by their stale request is unusable. I believe that the watcher's callback was never redefined with the new res object (after refresh). I do not know if my assumption is correct, and would like to hear other's thoughts on this as I am new to nodejs.

stopping postman after request is done

I am trying to create a Weather API using node. In my controller file, I have this code which is run for the /check route.
controller.js:
//Check Weather
exports.check = (req, res) => {
UserModel.check(req.body.city)
};
model.js:
//Check Weather
function getData(city) {
url = "something";
request(url, function (err, response, body) {
if(err){
console.log('error:', error);
} else {
console.log('body:', body);
}
});
}
exports.check = (city) => {
city = city.toLowerCase();
let values = getData(city);
console.log(city);
return(values);
};
route:
app.post('/check', [
UsersController.check
]);
When I run this, it functions properly and the correct thing is logged in the console. However, after I send a request in Postman and the console.log shows up, Postman seems to be hung up as seen in this pic. Is there anyway I can make it so that Postman stops sending the request after return or console.log?
Postman is waiting for a response from the server. Your code is not currently sending any response, so postman seems 'hung up' as it is waiting. Try changing the line saying UserModel.check(req.body.city) to say res.send(UserModel.check(req.body.city)) so it will send the data returned from your UserModel.check function back as the response. Alternatively, if you don't want to send back the returned value, you could just add res.send(PutWhateverYouWantSentHere) after the function call.

Making external get request with Express

so I have the following Scenario; I have a private API key that Angular will show in XHR request. To combat this, I decided to use Express as a proxy and make server side requests. However, I cannot seem to find documentation on how to make my own get requests.
Architecture:
Angular makes request to /api/external-api --> Express handles the route and makes request to externalURL with params in req.body.params and attaches API key from config.apiKey. The following is pseudocode to imitate what I'm trying to accomplish:
router.get('/external-api', (req, res) => {
externalRestGetRequest(externalURL, req.body.params, config.apiKey)
res.send({ /* get response here */})
}
You are half way there! You need something to make that request for you. Such as the npm library request.
In your route something like
var request = require('request');
router.get('/external-api', function(req, res){
request('http://www.google.com', function (error, response, body) {
console.log('error:', error); // Print the error if one occurred and handle it
console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received
res.send(body)
});
})
This allows you to make any type of request using whatever URL or API keys you need. However it's important to note you also need to handle any errors or bad response codes.
The accepted answer is good, but in case anyone comes across this question later, let's keep in mind that as of February, 2020, request is now deprecated.
So what can we do? We can use another library. I would suggest Axios.
Install it and do something like:
const axios = require('axios')
const url = "https://example.com"
const getData = async (url) => {
try {
const response = await axios.get(url)
const data = response.data
console.log(data)
} catch (error) {
console.log(error)
}
}
getData(url)

How to add/remove response headers in ExpressJS while proxying request

I have some files stored on a CDN server which is not to be directly accessed from client. So I proxy the requests via the public accessible server running ExpressJS and use request module to fetch the data server-side and return it in response.
It is working and in code looks something like this:
var request = require('request');
var app = express();
var internalUrl = 'https://my.storage-cdn.com/private/info/file.xml';
app.get('/somefile.xml', function (req, res) {
request(internalUrl).pipe(res);
});
The issues I faced with above method are:
the storage/cdn server appends some response headers of its own
which include some private information and as such can be a security
issue when exposed in response. And above method of piping the res
object to request doesn't remove those headers. It passes those
headers as is to response. I want to remove those headers.
I want to add some eTag and cache-control headers so the file could get cached
properly.
I have tried changing it to something like this:
app.get('/somefile.xml', function (req, res) {
request(internalUrl, function (err, response, body) {
if (!err && response.statusCode == 200) {
res.writeHead(200, {...}); // write custom headers I need
res.end(body);
}
});
});
This allows me to overwrite the headers to my liking, but in this method I have to wait for whole file to get downloaded on the server side first before I start sending the bytes in my response and with some files being as large as 1MB, it really affects the response time adversely.
So my question is - is there a way to not have to wait for whole file to download on server side before start sending response but still be able to manipulate response headers?
You can hook onto the 'response' event:
const SECRET_HEADERS = ['Set-Cookie', 'X-Special-Token']
app.get('/somefile.xml', function (req, res) {
request(internalUrl).on('response', function (response) {
SECRET_HEADERS.forEach(function (header) {
response.removeHeader(header)
})
}).pipe(res)
})

node.js. Problems saving requested zip file to disk

I'm having trouble saving a remote zip file to disk with with node.
I'm using request library to make requests. I want to request a zip file,
if the request is succesful write it to disk. I can't get a good combination of
correct error handling and writing the file.
I want to do the following :
request.get('https://example.com/example.zip', {
'auth': { 'bearer': accessToken },
}, function(error, response, body) {
// shortcircuit with notification if unsuccessful request
if (error) { return handleError() }
// I want to save to file only if no errors
// obviously this doesn't work because body is not a stream
// but this is where I want to handle it.
body.pipe(fs.createWriteStream('./output.zip'));
});
I know I can pipe the request directly as follows but I can't get decent error handling. The on error callback doesn't fire for 404s, and if I catch the request and throw an error if !response.ok the empty output file is still written to disk
request.get('https://example.com/example.zip', {
'auth': { 'bearer': accessToken },
})
.on('error', handleError)
.pipe(fs.createWriteStream('./output.zip'));
Instead of using body.pipe(), use response.pipe().
request.get('https://example.com/example.zip', {
auth: {
bearer: accessToken
}
}, (err, res, body) => {
if (res.statusCode !== 200) { // really should check 2xx instead
return handleError();
}
res.pipe(fs.createWriteStream('./output.zip');
});
The downside here though is that the request module is going to buffer the full response. Easy fix... don't use the request module. http.get() is fine and is a drop-in replacement.
Also, I highly recommend checking out the request-promise module which has an option for failing on 404.

Resources