Commit 10105eda authored by Pedro Eduardo Trujillo's avatar Pedro Eduardo Trujillo
Browse files

Mejora peticiones internas y controla errores

Mejora gestión de respuestas a peticiones internas, controlando errores
y mostrando feedback en la salida. Devuelve error genérico en formato
JSON al cliente en caso de error en la petición interna.

Refactoriza métodos de gestión de respuesta a peticiones internas para
aprovechar los mismos recursos en caso de error propio o de error en el
código de la respuesta.

Asigna cabecera de tipo de contenido a algunas respuestas.

Recibe URL de sitemap a través de variable de entorno.
parent 182795f9
Loading
Loading
Loading
Loading
+70 −27
Original line number Diff line number Diff line
@@ -9,7 +9,8 @@ let logger, params, version, robotsContent, sitemapContent, sitemapLastUpdated,
	oauthUrl = process.env.OAUTH_URL,
	oauthClientSecret = process.env.OAUTH_CLIENT_SECRET,
	production = !!parseInt(process.env.PRODUCTION, 10),
	apiUrl = process.env.API_URL;
	apiUrl = process.env.API_URL,
	sitemapUrl = process.env.SITEMAP_URL;

function getLang(req) {

@@ -59,7 +60,7 @@ function on404Request(_req, res) {
	res.render('404', { useBuilt: params.useBuilt });
}

function onOwnRequestSuccess(bindParams, internalRes) {
function onOwnRequestResponse(bindParams, internalRes) {

	let chunks = [];

@@ -70,33 +71,49 @@ function onOwnRequestSuccess(bindParams, internalRes) {

	internalRes.on('end', (function(nestedBindParams, nestedChunks) {

		let originalRes = nestedBindParams.res,
			internalResCallback = nestedBindParams.cbk,
			content = "";
		let content = "";

		for (let i = 0; i < nestedChunks.length; i++) {
			content += nestedChunks[i].toString();
		}

		originalRes.status(this.statusCode).send(content);
		let originalRes = nestedBindParams.originalRes,
			onSuccess = nestedBindParams.onSuccess || onOwnRequestSuccess,
			onError = nestedBindParams.onError || onOwnRequestError,
			afterResponse = nestedBindParams.afterResponse;

		if (this.statusCode < 400) {
			onSuccess.bind(this)(originalRes, content);
		} else {
			onError.bind(this)(originalRes, content);
		}

		if (internalResCallback) {
			internalResCallback(content);
		if (afterResponse) {
			afterResponse(this.statusCode, content);
		}
	}).bind(internalRes, bindParams, chunks));
}

function onOwnRequestError(bindParams, err) {
function onOwnRequestSuccess(originalRes, content) {

	let originalRes = bindParams.res,
		internalErrCallback = bindParams.cbk;
	originalRes.status(this.statusCode).send(content);

	logger.error(err);
	originalRes.sendStatus(500);
	let internalUrl = this.req.protocol + '//' + this.req.host + this.req.path,
		internalRequestMessage = `INTERNAL ${this.req.method} ${internalUrl} ${this.statusCode}`;

	if (internalErrCallback) {
		internalErrCallback(err);
	logger.info(internalRequestMessage);
}

function onOwnRequestError(originalRes, err) {

	originalRes.set('Content-Type', 'application/json');

	originalRes.status(500).send({
		code: 'Server error',
		description: 'Something went wrong at server. Please, try again.'
	});

	logger.error(err);
}

function onSitemapRequest(_req, res) {
@@ -106,17 +123,14 @@ function onSitemapRequest(_req, res) {
	let currTimestamp = Date.now();

	if (!sitemapContent || !sitemapContent.length || sitemapLastUpdated < currTimestamp - 300000) {
		let sitemapUrl = 'https://s3.eu-west-1.amazonaws.com/mediastorage.redmic/public/sitemap.xml';
		let afterResponseCallback = (status, content) => status ? sitemapContent = content : sitemapContent = '';

		let internalReq = https.request(sitemapUrl, onOwnRequestSuccess.bind(this, {
			res: res,
			cbk: (content) => sitemapContent = content
		let internalReq = https.request(sitemapUrl, onOwnRequestResponse.bind(this, {
			originalRes: res,
			afterResponse: afterResponseCallback
		}));

		internalReq.on('error', onOwnRequestError.bind(this, {
			res: res,
			cbk: () => sitemapContent = ''
		}));
		internalReq.on('error', onOwnRequestError.bind(this, res));

		internalReq.end();

@@ -164,6 +178,8 @@ function onUnknownRequest(_req, res, _next) {

function onOauthTokenRequest(req, res) {

	res.set('Content-Type', 'application/json');

	let body = req.body,

		clientId = body.clientid,
@@ -184,15 +200,42 @@ function onOauthTokenRequest(req, res) {
		}
	};

	let bindParams = {res: res};
	let internalReq = reqLibrary.request(getTokenUrl, options, onOwnRequestSuccess.bind(this, bindParams));
	internalReq.on('error', onOwnRequestError.bind(this, bindParams));
	let bindParams = {
		originalRes: res,
		onError: onOauthRequestError
	};

	let internalReq = reqLibrary.request(getTokenUrl, options, onOwnRequestResponse.bind(this, bindParams));

	internalReq.on('error', onOauthRequestError.bind(this, res));

	let bodyData = 'grant_type=password&username=' + username + '&password=' + password + '&scope=write';
	internalReq.write(bodyData);
	internalReq.end();
}

function onOauthRequestError(originalRes, err) {

	let error = JSON.parse(err),
		errorType = error.error,
		errorDescription = error.error_description;

	if (errorType === 'invalid_grant') {
		originalRes.set('Content-Type', 'application/json');

		originalRes.status(401).send({
			code: errorType,
			description: errorDescription
		});

		logger.error(err);

		return;
	}

	onOwnRequestError.bind(this)(originalRes, err);
}

function exposeRoutes(app) {

	app.get('/env', onEnvRequest)
+1 −0
Original line number Diff line number Diff line
@@ -3,5 +3,6 @@ NODE_IMAGE_TAG=18.1.0-alpine3.15
OAUTH_URL=https://api.domain/oauth
OAUTH_CLIENT_SECRET=secret
API_URL=https://api.domain
SITEMAP_URL=https://s3.eu-west-1.amazonaws.com/mediastorage.redmic/public/sitemap.xml
PUBLIC_HOSTNAME=change.me
TRAEFIK_ENTRYPOINT=http
+1 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ services:
      OAUTH_URL:
      OAUTH_CLIENT_SECRET:
      API_URL:
      SITEMAP_URL:
    networks:
      traefik-net:
      metric-net:
+2 −8
Original line number Diff line number Diff line
@@ -410,16 +410,10 @@ define([

			var status = response.status,
				error = response.error,
				data = response.data,
				description = error ? error : this.defaultErrorDescription;

			if (data && data.description) {
				description += ' - ' + data.description;
			}
				description = error || this.defaultErrorDescription;

			if (status) {
				description += ' - ' + status + ' - <a href="/feedback/' + status + '" target="_blank">' +
					this.i18n.contact + '</a>';
				description += ' - <a href="/feedback/' + status + '" target="_blank">' + this.i18n.contact + '</a>';
			}

			this._emitEvt('COMMUNICATION', {
+16 −10
Original line number Diff line number Diff line
@@ -353,19 +353,25 @@ define([
		_parseError: function(res) {

			var response = res.response,
				status = response.status;

			// TODO el server expressjs no debería responder con status bueno si le llega la petición a él, revisar
			if (status < 400) {
				status = 500;
			}
				status = response.status,
				data = response.data,
				error = res.message;

			if (data) {
				// TODO usar response.data directamente cuando no se envuelva la respuesta con error
			var data = response.data;
			if (data && data.error) {
				if (data.error && data.error instanceof Object) {
					data = data.error;
				}

				if (data.code) {
					error += ' - ' + data.code;
				}

				if (data.description) {
					error += ' - ' + data.description;
				}
			}

			return {
				status: status,
				data: data,
@@ -373,7 +379,7 @@ define([
				url: response.url,
				getHeader: response.getHeader,
				options: response.options,
				error: res.message
				error: error
			};
		},