Node.js and https certificate error handling - javascript

To make a long story short:
I'm building node app which making a request with https (the secure version of http). Whenever I miss-configure my request options, I'm having this error:
Node.js Hostname/IP doesn't match certificate's altnames
Great... except of the fact that the entire request code is wrapped with a valid try..catch block (which works just fine.. checked that already). The code is basically something like this:
try
{
https.request(options, (response) =>
{
// no way I making it so far this that error
}).end();
}
catch(ex)
{
// for some reason.. I'm not able to get here either
}
What I intend to do is to simply handle that error within my try..catch block
After reading some posts I've learned that this behavior is mainly because the tls module is automatically process the request and therefore making this error - this is a nice piece of information but it doesn't really help me to handle the exception.
Some other suggested to use this option:
rejectUnauthorized: false // BEWARE: security hazard!
But I rather not... so.. I guess my questions are:
Handling an error with a try..catch block should work here..right?
If not - is this behavior is by-design in node?
Can I wrap the code in any other way to handle this error?
Just to be clear - I'm not using any third-party lib (so there is no one to blame)
Any kind of help will be appreciated
Thanks

You need to add an 'error' event handler on the request object returned by https.request() to handle that kind of error. For example:
var req = https.request(options, (response) => {
// ...
});
req.on('error', (err) => {
console.log('request error', err);
});
req.end();
See this section in the node.js documentation about errors for more information.

Related

Api is not fetching in reactJs

I am trying to fetch food by its key. In postman api is working fine but is the forntend it has no response.
backend code
app.get('/foods/:key', (req, res) => {
foodsCollection.find({ key: req.params.key }).toArray((err, documents) => {
res.send(documents[0])
})
})
frontend code
const { key } = useParams()
const [foodById, setFoodById] = useState({})
useEffect(() => {
fetch(`http://localhost:5000/foods/${key}`)
.then((res) => res.json())
.then((data) => {
setFoodById(data)
})
}, [key])
Although you've added some images above, the most important is missing, namely, what are the Browser's Developer Tools stating the problem is. You should see some message in the Console tab, as well as in the Network tab for that particular request, if it is indeed being made. Until anyone sees this, it will be very difficult to help in fixing your problem.
If your not already, I suggest scaffolding any react app with create-react-app (CRA). This will give you a working app to start from. You can ignore CORS related issues in development, if using CRA, by adding "proxy": "http://localhost:5000", to your package.json file, see here for more on this method, but remember, this is only works for local development. You can also start Chrome to ignore Web Security by running it with the --disable-web-security flag e.g. chromium --disable-web-security, but that isn't a great idea really, more a way to quickly determine if you are having CORS problems, as Chrome masks some problems as CORS related, when in fact they aren't.
I'd also suggest changing your fetch code to use await, so instead you'd have:
const response = await fetch(`http://localhost:5000/foods/${key}`);
if (!response.ok) {
console.error(`Error message: ${response.statusText} ${response.status}`);
}
const result = response.json();
console.log(result);
This isn't necessary, but I've always found it way easier to read than the then/catch/finally method.
Reason for error
You need to stringify an object before sending it to the client with the JSON.stringify() method. When we exchange data to/from a web server, it must be a string.
Solution:
Proper way to send response to the client would to wrap the entire API in a try-catch block and explicitly specify the HTTP Status Code along with the stringified data in every response.
Note: Although 500 status code is used for error handling, you should choose one as per the use case.
app.get('/foods/:key', (req, res) => {
try {
/*
rest of the code
*/
foodsCollection.find({ key: req.params.key }).toArray((err, documents) => {
if (err) {
// 500 stands for internal server error
return res.status(500).send(JSON.stringify('Here goes a meaningful error message!'));
}
// 200 stands for success
res.status(200).send(JSON.stringify(documents[0]));
});
/*
rest of the code
*/
} catch (error) {
// 500 stands for internal server error
res.status(500).send(JSON.stringify('Here goes another meaningful error message!'));
}
})
The problem is that you haven't set the CORS headers of response in your backend code. and you are using different ports in your backend and frontend (5000 & 3000) so the Same Origin Policy disallows reading the remote resource, indicating that the request was blocked due to violating the CORS security rules.
you've to set the CORS headers.
you can install the CORS npm package and follow it's instructions to resolve the issue like this:
var express = require('express')
var cors = require('cors')
var app = express()
app.use(cors())
.
.
.
And one other issue that I'm seeing is that you've put the react-router default route before your specified path. so move the <route path="*"> after <route path="/foods/:key">

Web Share API fails on second execution

I implemented the navigator.share() function in my code. It works on the first call, but when I try to call it again through the same event, I get the NotAllowedError: The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.
I found out that this is usually caused by navigator.share() not being directly called by user input, formerly also if called in a fetch callback. However, today it should be allowed as part of a fetch callback. The behaviour is also strange considering that it works on the first try and just fails on consecutive ones.
Any ideas would be highly appreciated.
Most probably you are not catching the exception the API throws when the user cancels the share. I just tried canceling and then sharing again for a random article on my blog, and it worked. Here is the code I use:
const share = async () => {
try {
await navigator.share({
title: '',
text: `“${document.title}” by #tomayac:`,
url: document.querySelector('link[rel=canonical]').href,
});
} catch (err) {
console.warn(err.name, err.message);
}
};

Invoking Rest API from Lambda (JS; Web Console)

_
MY CHALLENGE:
I would like to access a third party Rest API from within my Lambda function. (e.g."http://www.mocky.io/v2/5c62a4523000004a00019907").
This will provide back a JSON file which I will then use for data extraction
_
MY CURRENT CODE:
var http = require('http');
exports.handler = function(event, context, callback) {
console.log('start request to Mocky');
http.get('http://www.mocky.io/v2/5c62a4523000004a00019907', function(res) {
console.log(res);
})
.on('error', function(e) {
console.log("Got error: " + e.message);
});
};
This does not throw an error but also does not seem to provide back the JSON
_
MY OPEN QUESTIONS:
1) How can I extract the JSON so that I can work on it
2) I will probably need to also send through an Authentification in the request header (Bearer) in the future. Will this also be possible with this method?
The problem is likely that your lambda function is exiting before logging the response.
We use Authorization headers all the time to call our lambdas. The issue of if you can use one to call the third party API is up to them, not you, so check the documentation.
Since your HTTP call is executed asynchronously, the execution of the lambda continues while that call is being resolved. Since there are no more commands in the lambda, it exits before your response returns and can be logged.
EDIT: the http.get module is difficult to use cleanly with async/await. I usually use superagent, axios, or request for that reason, or even node-fetch. I'll use request in my answer. If you must use the native module, then see EG this answer. Otherwise, npm install request request-promise and use my answer below.
The scheme that many people use these days for this kind of call uses async/await, for example (Requires Node 8+):
var request = require('request-promise')
exports.handler = async function(event, context, callback) {
console.log('start request to Mocky');
try {
const res = await request.get('http://www.mocky.io/v2/5c62a4523000004a00019907')
console.log(res)
callback(null, { statusCode: 200, body: JSON.stringify(res) })
}
catch(err) {
console.error(err.message)
callback('Got error ' + err.message)
}
};
The async/await version is much easier to follow IMO.
Everything inside an async function that is marked with await with be resolved before the execution continues. There are lots of articles about this around, try this one.
There are a lot of guys having an equal problem already solved... Look at that
or that

Node.js - Serving error 500 pages on unexpected errors

I'm trying to serve 500 pages (some generic HTML that says "500 - internal server error") from my Node.js server to requests that failed to resolve due to developer bugs, but can't find an elegant way to do this.
Lets say we have the following index.js, where a developer innocently made a mistake:
const http = require('http');
const port = 12345;
http.createServer(onHttpRequest).listen(port);
function onHttpRequest(req, res) {
var a = null;
var b = a.c; // this is the mistake
res.end('status: 200');
}
Trying to access property "c" of null throws an error, so "res.end" will never be reached. As a result, the requesting client will eventually get a timeout. Ideally, I my server to have code that can catch errors like this, and return 500 pages to the requesting client (as well as email an administrator and so on).
Using "try catch" in every single block is out of the question. Most Node.js code is async, and a lot of the code relies on external libraries with questionable error handling. Even if I use try-catch everywhere, there's a chance that an error would happen in an external library that didn't have a try-catch block inside of it, in a function that happens asynchronously, and thus my server will crash and the client would never get a response.
Shortest example I can provide:
/* my server's index.js */
const http = require('http');
const poorlyTestedNpmModule = require('some-npm-module');
const port = 12345;
http.createServer(onHttpRequest).listen(port);
function onHttpRequest(req, res) {
try {
poorlyTestedNpmModule(null, onResult);
}
catch(err) {
res.end('status: 500');
}
function onResult(err, expectedResult) {
if(err) {
res.end('status: 400');
}
else {
res.end('status: 200');
}
}
}
/* some-npm-module.js */
module.exports = function poorlyTestedNpmModule(options, callback) {
setTimeout(afterSomething, 100);
function afterSomething() {
var someValue = options.key; // here's the problem
callback(null, someValue);
}
}
Here, the server crashes, due to a function call that led to code that asynchronously throws an error. This code is not code that I control or wish to modify; I want my server to be able to handle all those errors on its own.
Now, I could, for instance, just use the global uncaughtException event, i.e.:
process.on('uncaughtException', doSomething);
but then I have no access to the (req, res) arguments, making it impossible to call res.end for the correct res instance; the only way to have access to them, is to store them in a higher-scope object for each incoming request, and then prune them on successful request resolutions, then mark existing [req, res] stored pairs as "potentially errored" whenever an uncaughtException triggers, and serve 500 pages to those requests whenever the count of currently-active requests matches the count of currently-unresolved-errors (and re-test that count per thrown uncaught expection and per successful res.end call).
Doing that works, but... it's ugly as hell. It means that request objects have to be leaked to the global scope, and it also means that my router module now has a dependency on the uncaughtException global event, and if any other code overwrites that event, everything breaks, or if I ever want to handle other uncaught exceptions for whatever reason, I'll run into cross dependency hell.
The root cause of this problem is that an unexpected error can happen anywhere, but I want to specifically catch whether an unexpected error originated from a stack trace that began from an incoming http request (and not, for example, from some interval I have running in the background, because then I get an unexpected error but obviously don't want to serve a 500 page to anyone, only email an admin with an error log), and on top of needing to know whether the error originated from an http request, I need to have access to the request+response objects that node server objects provide.
Is there no better way?
[Edit] The topic of this question is role distribution in modules.
i.e., one guy is making base code for a server, lets say a "router module". Other people will add new code to the server in the future, handling branches that are routed to.
The guy that writes the base server code has to write it in a way that it will serve 500 pages if any future code is written incorrectly and throws errors. Help him accomplish his goal.
Answers of the format "make sure all future people that add code never make mistakes and always write code that won't throw uncaught errors" will not be accepted.
At first, using uncaughtException in Nodejs is not safe. If you feel that there is no other option in your application, make sure that you exit the process in the handler of 'uncaughtException' and restart the process using pm2 or forever or someother modules. Below link can provide you its reference.
Catch all uncaughtException for Node js app
Coming to the process of error handling, as mentioned, you may always miss to handle errors with callback. To avoid, these we can use an exceptional advantage of promises in nodejs.
/* my server's index.js */
const http = require('http');
const poorlyTestedNpmModule = require('some-npm-module');
const port = 12345;
http.createServer(onHttpRequest).listen(port);
function onHttpRequest(req, res) {
try {
poorlyTestedNpmModule(null)
.then(result => {
res.end('status: 200');
})
.catch(err =>{
console.log('err is', err);
res.end('status: 400');
})
}
catch(err) {
res.end('status: 500');
}
}
/* some-npm-module.js */
module.exports = function poorlyTestedNpmModule(options, callback) {
setTimeout(afterSomething, 100);
afterSomthing = new Promise((resolve, reject)=> {
var someValue = options.key; // here's the problem
resolve(someValue);
})
}
If you see that some of the npm nodemodules are not present with promise, try to write wrappers to convert callback to promise model and use them in your application.

How to modify response headers with express-http-proxy

Background
I'm using express-http-proxy to proxy a handful of requests between my SPA (single page application) and a CouchDB instance. I'm doing this proxy on a per call basis, NOT creating a proxy server (this will be important in a moment).
example of current use
app.use(`some/url`, proxy(dburl, {
forwardPath: req => {return 'some/url'+require('url').parse(req.url).path;}
}) );
Which means I am NOT using httpProxy.createServer. I want to send some snippet of text data along with my responses as a header. After looking through the documentation I've come to the conclusion that what I want will be using intercept. Unfortunately I've not quite managed to grasp how to use it, and the only related questions I've found so far appear to be based on httpProxy.createServer which appears (from my limited understanding) to work differently.
We are using individual request proxying because we wish to proxy different requests to different micro-services, and found this to be the most concise way (that we knew of & at the time) of doing that.
The Question
Given the code
const text = 'asdf';
app.use(`some/url`, proxy(dburl, {
forwardPath: req => {return 'some/url'+require('url').parse(req.url).path;},
intercept: function(rsp, data, req, res, callback) {
//SUSPECT LOCATION
}
}) );
Is there some code at SUSPECT LOCATION which would allow me to place text on the header for the final response without further affects to the (currently otherwise working) proxy?
Additional Notes
Headers and network requests in general are not very familiar to me, my apologies if the answer seems self evident.
Bonus points for a link to a resource that helps explain either the finer points of using this library for proxying, a similar library for proxying, or the underlying technologies which would make it clear how to use this library for proxying. AKA I'd rather spend some of my own time looking further into this and not come back for further questions.
I am not entirely confident that the place for my code will be SUSPECT LOCATION and I will happily listen if it needs to go somewhere else, or if we need to approach this problem in a different way.
The accepted answer is now outdated.
Intercept does not exist anymore.
Instead, use your own middleware before the proxy function
router.route('/my-route').get((req, res, next) => {
res.set('My-Header', 'my-header-value');
next();
}, proxyFunction);
It follows express.js methods on req, res objects.
Within the intercept function body, set the response headers using the following express format.
res.set('hola', 'amigos!!!');
Refer below link:
http://expressjs.com/en/4x/api.html#res.set
The best way to understand a library when there is no documentation is to follow its test suite. If there is no test suite don't use that library.
This is the test suite for the express-http-proxy intercept function
https://github.com/villadora/express-http-proxy/blob/master/test/intercept.js
This is the test case
it('can modify the response headers', function(done) {
var app = express();
app.use(proxy('httpbin.org', {
intercept: function(rsp, data, req, res, cb) {
res.set('x-wombat-alliance', 'mammels');
res.set('content-type', 'wiki/wiki');
cb(null, data);
}
}));
request(app)
.get('/ip')
.end(function(err, res) {
if (err) { return done(err); }
assert(res.headers['content-type'] === 'wiki/wiki');
assert(res.headers['x-wombat-alliance'] === 'mammels');
done();
});
});
If you want to undetstand in and out of proxying, the best resource is haproxy
http://cbonte.github.io/haproxy-dconv/1.7/intro.html
But before that you need to understand http more (a constructive comment)

Categories