Override default `Expect: 100-continue` behaviour in Firebase Functions - node.js

By default, requests sent to a Firebase Function with the Expect header set to 100-continue automatically reply with 100 Continue. We have a partner who sends requests with this header erroneously set, and replying with "100 Continue" is treated as a failure on their end. After the first request, our route handlers stop running (using Firebase emulator).
I tried the following:
app.on('checkContinue', ((req: any, res: any) => {
console.log('checkContinue');
return app(req, res);
}) as any);
app.on('checkExpectation', ((req: any, res: any) => {
console.log('checkExpectation');
return app(req, res);
}) as any);
I don't see anything in console logs (running Firebase Functions emulator).

Related

Piping response through express slow

I am using express as a proxy server between a webapp and a remote backend service.
When piping responses through express, the response times are extremely slow.
Example (all services run locally on the same machine, tested with Postman, also running locally)
:8081 is the backend service, :4000 is the express proxy service
Fetching localhost:8081/api/assets/1 takes about 50ms. Absolutley fine.
But fetching localhost:4000/assets/1 takes 5 seconds
The code itself (to me) doesn't seem to indicate why this would take this much longer:
export const proxyApiCall = async (req: Request, res: Response, fullPath: string) => {
try {
const response = await backend.fetch(fullPath); // node-fetch with some additional headers
["content-type", "content-length", "last-modified", "cache-control"].forEach((name) => {
const value = response.headers.get(name);
if (value) {
res.setHeader(name, value);
}
});
res.status(response.status);
response.body.pipe(res);
} catch (err) {
LOG.error(err);
res.sendStatus(500);
}
};

axios-retry not working as expected. What is wrong with my config?

I have configured axios-retry in my nodejs application as per https://www.npmjs.com/package/axios-retry
Following is my code
import axios from 'axios';
import axiosRetry from 'axios-retry';
export class RetryRoute {
public async testRetry(
req: express.Request,
res: express.Response,
next: express.NextFunction,
): Promise<any> {
const client = axios.create({ baseURL: `http://www.test.com/` });
axiosRetry(axios, { retries: 3 });
client.get('/error')
.then(result => {
this.logger.info('success', result);
result.data;
}).catch(error => {
console.log('error', error.message);
error !== undefined
});
}
}
console.log('error', error.message);. prints as expected. which means call is failed with code 404 as expected. But next call from retry not happening.
You need to specify retry condition, below code retry for every failed request
axiosRetry(axios, {
retries: 3,
retryCondition: () => true
});
From https://github.com/softonic/axios-retry
By default, it retries if it is a network error or a 5xx error on an
idempotent request (GET, HEAD, OPTIONS, PUT or DELETE).
A http 404 status code means the request was handled successfully but was invalid. It doesn't retry in this case as it would expect the retry to also fail presumably with almost 100% certainty. 404 errors shouldn't be transient in the same way 500 errors or network errors may be.

How to handle "UnhandledPromiseRejectionWarning" in Fastify without "async / await" or ".catch"

I'm running a simple Fastify server and when I make a request and it fails, I wanna handle that exception in the setErrorHandler.
How can I achieve that?
This doesn't seem to work:
import fastify from 'fastify';
import fetch from 'node-fetch';
const app = fastify();
app.setErrorHandler(async (error, request, response) => {
// I want this to be called whenever there is an error
console.log('setErrorHandler');
return 'error';
});
app.get('/', (request, response) => {
// I do not want to use async / await or .catch here
fetch('https://...').then(() => { response.send(); });
});
I get the error UnhandledPromiseRejectionWarning and the server never sends a response.
I do NOT want to use async, await or .catch on the promise. The reason is I'm simulating a developer error. So if someone forgets to add a .catch and is not using async / await, I still wanna "catch" that error and return status 500 to the client.
I'm willing to change / wrap the request library adding a .catch in it, I just don't wanna change that endpoint handler code in general, since it's sort of out of my control (another developer might code it any way they want).
The reason is I'm simulating a developer error.
You can't manage these errors at runtime to reply to a request because you don't reference the reply object to act accordingly.
You can catch those errors with, but the reply cannot be fulfilled:
process.on('unhandledRejection', (err) => {
console.log(err)
})
As an alternative, I would set connectionTimeout, so the client will get a timeout error at least.
As you wrote, you already know that you should change the handler code to let Fastify be aware of the promise:
// add return
app.get('/', (request, response) => {
return fetch('https://...').then(() => { response.send(); });
})
For this reason, I think the solution to your problem should be taken offline adding a linter rule (like so) and integrate some Static Code Analysis in the CI pipeline to reject bad code.

Finalize on http interceptor not being hit when token expires

I'm trying my hand at MEAN for the first time and I'm coming up against some resistance with error handling on jwt token expiration. I've got the error handler here on the express server.
const handleUnauthorisedError = (err: any, req: any, res: express.Response, next: any) => {
if (err.name === "UnauthorizedError") {
if (err.message === "jwt expired") {
res.header("Token-Expired", "true");
}
console.error(err);
res.status(401);
return res.json({ message: `${err.name}: ${err.message}` }).end();
}
};
Which is then being added here after the routes.
app.use("/api", setupRoutes());
app.use(handleUnauthorisedError);
Within my angular interceptor I've got this error handler
private handle401Error = (err: HttpErrorResponse, req: HttpRequest<any>, next: HttpHandler) => {
console.log(err.headers);
if (err.headers.has("Token-Expired")) {
this.tokenSubject.next(null);
return this.authenticationService.refresh().pipe(switchMap(() => {
return next.handle(this.addToken(req));
}), catchError(() => {
return this.authenticationService.logoutExpired().pipe(finalize(() => {
this.router.navigate(["/login"]);
}));
}));
}
return this.authenticationService.logoutExpired().pipe(finalize(() => {
this.router.navigate(["/login"]);
}));
}
However finalize never seems to occur, unless I terminate the express server. It's as if the connection is persisting maybe?
Z
I think finalize does not occur because this operator works when the source completes or throws an error. More on this here.
Think of the finalize operator as the finally statement from try/catch.
In your code, you are only emitting values.
Another question that arises is why would you use finalize?
I'd use this when I'm dealing with http calls.
But, if for some reason you still want to use this operator, you could make sure that you throw an error from this.authenticationService.logoutExpired():
logoutExpired () {
// Some logic here..
return throwError('err');
}
Here is a little StackBlitz demo.

Request and Response Lifecyle in Node and Express

I have a very simple route setup for my web app,
router.get('/myTestRoute/:id', async (req: Request, res: Response, next: NextFunction) => {
await doSomeAsync(req, res);
res.json({ myObj: 32 });
return next();
}
The doSomeAsync actually performs a request to a service and takes up to 20 seconds. However the response that the user is looking for doesn't need or care about the doSomeAsync response, so I thought I could remove the await, so that it would look like this:
router.get('/myTestRoute/:id', async (req: Request, res: Response, next: NextFunction) => {
doSomeAsync(req, res);
res.json({ myObj: 32 });
return next();
}
Inside the doSomeAsync function, after the service call, we reference parameters on the req and res objects, like the parameters on the req object, and some authentication stuff on the res object.
I have found that this is not working, and I realized that I don't fully understand what happens with req and res after the response has been sent back to the user.
After I call res.json(), and then next(), what happens to the Request and Response objects, do they reset? Do they change in any way?
Should I refactor doSomeAsync() to accept the primitive values from req.params?

Resources