UNPKG

geoportal-access-lib

Version:

French Geoportal resources access library

420 lines (374 loc) 17 kB
/* global Promise, require, XDomainRequest */ import Logger from "../Utils/LoggerByDefault"; import Helper from "../Utils/Helper"; import ES6Promise from "es6-promise"; // import __request from "request"; // import __xmldom from "xmldom"; /** * Ajax Request (use of Promises) * * @module XHR * @alias Gp.Protocols.XHR * @see dependance 'es6-promise' */ // cf. https://xhr.spec.whatwg.org/ // cf. https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest var XHR = { /** * Interface unique d'envoi d'une requête. * * @method call * @static * @param {Object} settings - options generales * @param {String} settings.url - url du service * @param {String} settings.method - GET, POST, PUT, DELETE * @param {String} settings.format - format de la reponse du service : json, xml ou null (brute) * @param {String} settings.data - content (post) ou param (get) * @param {String} settings.proxy - proxy url * @param {Object|String} settings.headers - (post) ex. referer * @param {Object|String} settings.content - (post) ex. 'application/json' * @param {String} settings.timeOut - timeout = 0 par defaut * @param {String} settings.scope - this * @param {Function} settings.onResponse - callback * @param {Function} settings.onFailure - callback */ call : function (settings) { // logger var logger = Logger.getLogger("XHR"); logger.trace("[XHR::call()]"); // FIXME // To polyfill the global environment ES6Promise.polyfill(); // test sur les settings obligatoires if (!settings.url) { throw new Error("missing parameter : url is not defined !"); } if (!settings.method) { throw new Error("missing parameter : method is not defined !"); } if (!settings.format) { settings.format = "text"; // reponse brute ! } var options = {}; options.url = settings.url; options.data = settings.data ? settings.data : null; options.method = settings.method; options.timeOut = settings.timeOut || 0; options.scope = settings.scope || this; options.proxy = settings.proxy || null; options.content = settings.content || null; options.headers = settings.headers || { referer : "http://localhost" }; // test sur les valeurs de 'settings.method' switch (settings.method) { case "DELETE": case "GET": break; case "PUT": case "POST": // on force sur ces params spécifiques au mode POST options.content = settings.content ? settings.content : "application/x-www-form-urlencoded"; // FIXME en attente des services : bascule en "application/xml" ou "application/json" options.headers = settings.headers ? settings.headers : { referer : "http://localhost" }; // FIXME parametrable... break; case "HEAD": case "OPTIONS": throw new Error("HTTP method not yet supported !"); default: throw new Error("HTTP method unknown !"); } // test sur les valeurs de 'settings.format' switch (settings.format) { case "text": this.__call(options) .then(function (response) { logger.trace(response); settings.onResponse.call(this, response); }) .catch(function (error) { settings.onFailure.call(this, error); }); break; case "json": this.__callJSON(options) .then(function (response) { logger.trace(response); settings.onResponse.call(this, response); }) .catch(function (error) { settings.onFailure.call(this, error); }); break; case "xml": this.__callXML(options) .then(function (response) { logger.trace(response); settings.onResponse.call(this, response); }) .catch(function (error) { settings.onFailure.call(this, error); }); break; default: throw new Error("This output Format is not yet supported !"); } }, /** * Requete * * @method __call * @private * @param {Object} options - options * @return {Object} promise */ __call : function (options) { var logger = Logger.getLogger("XHR"); logger.trace("[XHR::__call()]"); var promise = new Promise( function (resolve, reject) { // traitement du corps de la requête var corps = (options.method === "POST" || options.method === "PUT") ? 1 : 0; // seulement si options.data n'est pas vide (peut être un objet ou une chaine de caractères) if (options.data && ((typeof options.data === "object" && Object.keys(options.data).length) || (typeof options.data === "string" && options.data.length)) && !corps) { options.url = Helper.normalyzeUrl(options.url, options.data); } logger.trace("URL = ", options.url); var hXHR = null; // test on env. nodejs or browser if (typeof window === "undefined") { var nodefetch = require("node-fetch"); var opts = { headers : { Referer : "https://localhost" } }; if (options.data && typeof options.data === "string" && corps) { opts = { method : options.method, body : options.data, headers : { "Content-Type" : options.content, Referer : "https://localhost" } }; } return nodefetch(options.url, opts) .then(function (response) { if (response.ok) { // res.status >= 200 && res.status < 300 resolve(response.text()); } else { var message = "Errors Occured on Http Request (status : '" + response.statusText + "' | url : '" + response.url + "')"; var status = response.status; reject({ message : message, status : status }); } }) .catch(function (e) { reject({ message : e, status : -1 }); }); } else { if (window.XMLHttpRequest) { logger.trace("XMLHttpRequest"); hXHR = new XMLHttpRequest(); hXHR.open(options.method, options.url, true); // async hXHR.overrideMimeType = options.content; // gestion du timeout var onTimeOutTrigger = null; if (options.timeOut > 0) { // FIXME le timeout interne ne me permet pas de declencher le bon message... // hXHR.timeout = options.timeOut; logger.trace("XHR - TimeOut actif !"); /** * Description * * @method onTimeOutTrigger * @private */ onTimeOutTrigger = window.setTimeout( function () { var message = "TimeOut Occured on Http Request with XMLHttpRequest !"; reject({ message : message, status : -1 }); }, options.timeOut); } if (corps) { // headers, data, content of data // cf. https://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html#dom-xmlhttprequest-setrequestheader logger.trace("data = ", options.data); hXHR.setRequestHeader("Content-type", options.content); // FIXME refused to set unsafe header content-length javascript // hXHR.setRequestHeader ("Content-length", options.data.length); // hXHR.setRequestHeader ("Referer", options.headers.referer); } /** * On Error * FIXME ne se declenche pas !? * * @param {Object} e - Event * @method onerror * @private */ hXHR.onerror = function (e) { console.log(e); reject(new Error("Errors Occured on Http Request with XMLHttpRequest !")); }; /** * On Timeout * FIXME ne se declenche pas !? * * @param {Object} e - Event * @method ontimeout * @private */ hXHR.ontimeout = function (e) { console.log(e); reject(new Error("TimeOut Occured on Http Request with XMLHttpRequest !")); }; /** * Description * * @method onreadystatechange * @private */ hXHR.onreadystatechange = function (e) { if (hXHR.readyState === 4) { // DONE if (hXHR.status === 200) { window.clearTimeout(onTimeOutTrigger); resolve(hXHR.response); } else { var message = "Errors Occured on Http Request (status : '" + e.target.statusText + "' | url : '" + e.target.responseURL + "' | response : '" + e.target.response + "')"; var status = e.target.status; reject({ message : message, status : status }); } } }; // gestion du content data var data4xhr = (options.data && corps) ? options.data : null; hXHR.send(data4xhr); } else if (window.XDomainRequest) { // worked in Internet Explorer 8–10 only ! logger.trace("XDomainRequest"); hXHR = new XDomainRequest(); hXHR.open(options.method, options.url); hXHR.overrideMimeType = options.content; if (options.timeOut > 0) { hXHR.timeout = options.timeout; logger.trace("XHR - TimeOut actif !"); } if (corps) { // headers, data, content of data // cf. https://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html#dom-xmlhttprequest-setrequestheader hXHR.setRequestHeader("Content-type", options.content); // FIXME refused to set unsafe header content-length javascript // hXHR.setRequestHeader ("Content-length", options.data.length); // hXHR.setRequestHeader ("Referer", options.headers.referer); } /** * Description * * @method onerror * @private */ hXHR.onerror = function () { reject(new Error("Errors Occured on Http Request with XMLHttpRequest !")); }; /** * Description * * @method ontimeout * @private */ hXHR.ontimeout = function () { reject(new Error("TimeOut Occured on Http Request with XMLHttpRequest !")); }; /** * On Load * * @method onload * @private */ hXHR.onload = function (e) { if (hXHR.status === 200) { resolve(hXHR.responseText); } else { var message = "Errors Occured on Http Request (status : '" + e.target.statusText + "' | url : '" + e.target.responseURL + "')"; var status = e.target.status; reject({ message : message, status : status }); } }; var data4xdr = (options.data && corps) ? options.data : null; hXHR.send(data4xdr); } else { throw new Error("CORS not supported"); } } } ); return promise; }, /** * Requete avec parser JSON * * @method __callJSON * @private * @param {Object} options - options * @return {Object} promise */ __callJSON : function (options) { return this.__call(options) .then(JSON.parse) .catch(function (error) { console.log("_callJSON failed on : ", options.url, error); // FIXME pas d'exception, laissons le fil se derouler... // throw error; }); }, /** * Requete avec parser XML * * @method __callXML * @private * @param {Object} options - options * @return {Object} promise */ __callXML : function (options) { return this.__call(options) .then(function (response) { var xmlDoc; // test on env. nodejs or browser if (typeof window === "undefined") { var DOMParser = require("@xmldom/xmldom").DOMParser; // __xmldom.DOMParser xmlDoc = new DOMParser().parseFromString(response, "text/xml"); } else { if (window.DOMParser) { var parser = new window.DOMParser(); xmlDoc = parser.parseFromString(response, "text/xml"); } else { // IE xmlDoc = new window.ActiveXObject("Microsoft.XMLDOM"); xmlDoc.async = false; xmlDoc.loadXML(response); } } return xmlDoc; }) .catch(function (error) { console.log("__callXML failed on : ", options.url, error); // FIXME pas d'exception, laissons le fil se derouler... // throw error; }); } }; export default XHR;