geoportal-access-lib
Version:
French Geoportal resources access library
420 lines (374 loc) • 17 kB
JavaScript
/* 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;