4 votos

OpenLayers 3 WMS Styling Usando SLD_BODY y petición POST

Estoy utilizando OpenLayers 3 y GeoServer para crear una aplicación web espacial en la que quiero permitir a los usuarios elegir una rampa de color (utilizando Colorbrewer) y un número de saltos para estilizar un atributo en su capa de análisis (es decir, para estilizar un choropleth). He conseguido que esto funcione generando dinámicamente una cadena XML SLD y pasándola como valor al parámetro SLD_BODY en la fuente TileWMS, pero sólo con 3 saltos/clases. Cuando selecciono 4 o más clases no se devuelve nada y creo que el problema es que el SLD se vuelve demasiado largo para la petición GET de OpenLayers TileWMS. He leído varios posts que explican que se puede hacer una petición POST en OpenLayers 2 para evitar este problema, pero no he encontrado nada sobre cómo hacer esto usando OpenLayers 3. Sólo una respuesta en este puesto insinúa una solución, pero no es suficiente para que yo encuentre una respuesta. Así es como estoy definiendo la capa y añadiendo el SLD. ¿Alguien sabe cómo evitar el límite de caracteres con la solicitud GET de OpenLayers 3 utilizando POST en su lugar?

window.layer = new ol.layer.Tile({
  source: new ol.source.TileWMS({
   url: 'http://' + window.location.hostname + ':8080/geoserver/wms',
   params: {LAYERS: geoserverLayer, STYLES: undefined, SLD_BODY: sld, CQL_FILER: geoserverFilter, TILED: true},
   serverType: 'geoserver'
  })
});

6voto

Gunny Puntos 16

No estoy seguro de que mi respuesta vaya a darle la solución definitiva. Pero inténtalo y haznos saber si surge algo bueno. Haz lo siguiente:

  1. añadir tileLoadFunction a su fuente. Así:

    window.layer = new ol.layer.Tile({
    source: new ol.source.TileWMS({
    url: 'http://' + window.location.hostname + ':8080/geoserver/wms',
    params: {LAYERS: geoserverLayer, STYLES: undefined, SLD_BODY: sld, CQL_FILER: geoserverFilter, TILED: true},
    serverType: 'geoserver',
    tileLoadFunction: function(image, src) {
       imagePostFunction(image, src);
    }
    })
    });
  2. crea tu función personalizada imagePostFunction así:

    function imagePostFunction(image, src) {
    var img = image.getImage();
    if (typeof window.btoa === 'function') {
     var xhr = new XMLHttpRequest();
     xhr.open('POST', src, true);
     xhr.responseType = 'arraybuffer';
     xhr.onload = function(e) {
     if (this.status === 200) {
      console.log("this.response",this.response);
      var uInt8Array = new Uint8Array(this.response);
      var i = uInt8Array.length;
      var binaryString = new Array(i);
      while (i--) {
        binaryString[i] = String.fromCharCode(uInt8Array[i]);
      }
      var data = binaryString.join('');
      var type = xhr.getResponseHeader('content-type');
      if (type.indexOf('image') === 0) {
        img.src = 'data:' + type + ';base64,' + window.btoa(data);
      }
    }
    };
    xhr.send();
    } else {
    img.src = src;
    }
    }

    Debería forzar a ol3 a ejecutar una petición POST pero no estoy seguro de si se van a pasar parámetros al cuerpo POST de la petición y así resolver el problema de la url larga.

También hay que tener en cuenta lo siguiente Correo electrónico: podría ayudar. De cualquier manera, por favor, háganos saber si funciona.

ACTUALIZAR AQUÍ PARA imagePostFunction

function imagePostFunction(image, src) {
var img = image.getImage();
if (typeof window.btoa === 'function') {
  var xhr = new XMLHttpRequest();
  console.log("src",src);
  **//GET ALL THE PARAMETERS OUT OF THE SOURCE URL**
  var dataEntries = src.split("&");
  var url;
  var params = "";
  for (var i = 0 ; i< dataEntries.length ; i++){
      console.log("dataEntries[i]",dataEntries[i]);
      if (i===0){
      url = dataEntries[i];    
      }
      else{
      params = params + "&"+dataEntries[i];
      }
  }
  console.log("params",params);
  xhr.open('POST', url, true);

  xhr.responseType = 'arraybuffer';
  xhr.onload = function(e) {
    if (this.status === 200) {
      console.log("this.response",this.response);
      var uInt8Array = new Uint8Array(this.response);
      var i = uInt8Array.length;
      var binaryString = new Array(i);
      while (i--) {
        binaryString[i] = String.fromCharCode(uInt8Array[i]);
      }
      var data = binaryString.join('');
      var type = xhr.getResponseHeader('content-type');
      if (type.indexOf('image') === 0) {
        img.src = 'data:' + type + ';base64,' + window.btoa(data);
      }
    }
  };
  //SET THE PROPER HEADERS AND FINALLY SEND THE PARAMETERS 
  xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  xhr.setRequestHeader("Content-length", params.length);
  xhr.setRequestHeader("Connection", "close");
  xhr.send(params);
} else {
  img.src = src;
}
}

3voto

Matthieu Cartier Puntos 161

He podido encontrar una solución a la petición POST de OL3 WMS basándome en la solución ofrecida anteriormente por @pavlos. Tuve que mover la petición HTTP al servidor para evitar el problema de CORS que me estaba encontrando. Estoy usando el framework Meteor así que mi código de servidor está en Javascript, y sólo tuve que añadir el http-extras por aldeed para poder especificar un responseType de 'buffer', que evita cualquier codificación de la respuesta. Abajo está mi código del lado del cliente. La clave aquí fue mantener la url base y los params separados, y no pasar src presente como un argumento en la tileLoadFunction a la petición HTTP, ya que src incluye todos los parámetros en una cadena de consulta y eso hace que la url sea demasiado larga. En su lugar, he pasado los parámetros a la petición HTTP en el servidor, que los incorpora en el cuerpo de la petición.

var url = 'http://' + window.location.hostname + ':8080/geoserver/wms';
  window.mceLayer = new ol.layer.Tile({
    source: new ol.source.TileWMS({
      url: 'http://' + window.location.hostname + ':8080/geoserver/wms',
      params: {LAYERS: geoserverLayer, STYLES: undefined, SLD_BODY: sld, CQL_FILER: geoserverMceFilter, TILED: true},
      serverType: 'geoserver',
      tileLoadFunction: function (image, src) {
        var img = image.getImage();
        var query = src.replace(url + '?', '');
        var params = getQueryParams(query); // A separate function to decode the query string into a JSON object.
        if (typeof window.btoa === 'function') {
          Meteor.call('geoserverWms', 'POST', url, params, function(err, result) {
            if (err) {
              return console.error('err:', err);
            }
            // console.log(result);
            var type = 'image/png';
            img.src = 'data:' + type + ';base64,' + result;
          });
        } else {
          img.src = src;
        }
      }
    })
  });

En la petición HTTP Post en el servidor, establecí el content-type como 'application/x-www-form-urlencoded' y el responseType como 'buffer'. Luego hice que mi función del servidor devolviera el contenido de la respuesta como una cadena base64. Véase más abajo.

geoserverWms: function (method, url, params) {
    var options = {
      headers: {'Content-Type': 'application/x-www-form-urlencoded'},
      params: params,
      responseType: 'buffer'
    }
    var result = HTTP.call(method, url, options);
    console.log('Content:', result.content);
    return result.content.toString('base64');
  }

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X