Работа с WFS

Работа с WFS (Web Feature Service) в OpenLayers основана на стандарте OGC, который позволяет получать географические объекты (features) с сервера в формате GML или GeoJSON через HTTP-запросы. WFS предоставляет доступ не к тайлам изображений, а к «живым» геообъектам с атрибутами и геометрией, что делает его ключевым механизмом для аналитических и редактируемых ГИС-приложений.

Архитектура взаимодействия с WFS

WFS работает по принципу запрос-ответ:

  • GetCapabilities — описание доступных слоёв и операций
  • DescribeFeatureType — описание структуры объектов
  • GetFeature — получение геометрий и атрибутов
  • Transaction (WFS-T) — вставка, обновление и удаление объектов

OpenLayers не реализует протокол WFS напрямую как отдельный клиент, но предоставляет инструменты через:

  • ol/format/WFS — формирование XML-запросов
  • ol/format/GML — парсинг ответов
  • ol/source/Vector — источник данных
  • ol/strategy/bbox — стратегия подгрузки по рамке

Базовая загрузка данных WFS

Наиболее распространённая схема — использование VectorSource с ручной генерацией запроса GetFeature.

import VectorSource from 'ol/source/Vector';
import GeoJSON from 'ol/format/GeoJSON';

const source = new VectorSource({
  format: new GeoJSON(),
  loader: function (extent, resolution, projection) {
    const url =
      'https://example.com/geoserver/wfs?' +
      'service=WFS&' +
      'version=2.0.0&' +
      'request=GetFeature&' +
      'typeName=workspace:layer&' +
      'outputFormat=application/json&' +
      'srsname=EPSG:3857&' +
      'bbox=' + extent.join(',') + ',EPSG:3857';

    fetch(url)
      .then(response => response.json())
      .then(data => {
        const features = source.getFormat().readFeatures(data, {
          featureProjection: projection
        });
        source.addFeatures(features);
      });
  }
});

Ключевой момент — использование bbox, который ограничивает объём загружаемых данных текущим видимым экстентом карты.

Стратегия загрузки данных

Для производительных приложений применяется стратегия bbox:

import {bbox as bboxStrategy} from 'ol/loadingstrategy';

const source = new VectorSource({
  format: new GeoJSON(),
  url: function (extent) {
    return (
      'https://example.com/geoserver/wfs?' +
      'service=WFS&version=2.0.0&request=GetFeature&' +
      'typeName=workspace:layer&outputFormat=application/json&' +
      'srsname=EPSG:3857&bbox=' +
      extent.join(',') +
      ',EPSG:3857'
    );
  },
  strategy: bboxStrategy
});

Стратегия обеспечивает автоматическую подгрузку данных при изменении области видимости карты.

Форматы данных: GML и GeoJSON

WFS традиционно возвращает GML, однако GeoJSON стал де-факто стандартом в веб-картографии.

GML через ol/format/WFS

import WFS from 'ol/format/WFS';

const wfsFormat = new WFS();

const featureRequest = wfsFormat.writeGetFeature({
  srsName: 'EPSG:3857',
  featurePrefix: 'workspace',
  featureTypes: ['layer'],
  outputFormat: 'application/json'
});

Чтение GML

import GML2 from 'ol/format/GML2';

const format = new GML2();

const features = format.readFeatures(xmlResponse, {
  featureProjection: 'EPSG:3857'
});

Ограничение выборки: фильтры CQL и OGC Filter

WFS поддерживает фильтрацию данных на сервере, что критично для производительности.

Атрибутивный фильтр

const url =
  'https://example.com/geoserver/wfs?' +
  'service=WFS&version=2.0.0&request=GetFeature&' +
  'typeName=workspace:layer&' +
  'cql_filter=population>10000';

Пространственный фильтр

const cql =
  'INTERSECTS(geom, POLYGON((...)))';

Использование OGC Filter Encoding

import WFS from 'ol/format/WFS';
import Filter from 'ol/format/filter';

const filter = Filter.and(
  Filter.like('name', 'Park*'),
  Filter.greaterThan('area', 500)
);

const wfs = new WFS();

const request = wfs.writeGetFeature({
  featureTypes: ['layer'],
  filter: filter
});

WFS-T: редактирование объектов

WFS-T (Transaction) позволяет изменять данные на сервере: добавлять, обновлять и удалять геометрию.

Добавление объекта

const wfs = new WFS();

const insertFeature = wfs.writeTransaction(
  [feature],
  null,
  null,
  {
    featureType: 'layer',
    featureNS: 'http://example.com/workspace',
    srsName: 'EPSG:3857'
  }
);

Обновление объекта

wfs.writeTransaction(
  null,
  [feature],
  null,
  {
    featureType: 'layer',
    featureNS: 'http://example.com/workspace'
  }
);

Удаление объекта

wfs.writeTransaction(
  null,
  null,
  [feature],
  {
    featureType: 'layer',
    featureNS: 'http://example.com/workspace'
  }
);

Отправка запроса:

fetch('https://example.com/geoserver/wfs', {
  method: 'POST',
  headers: {
    'Content-Type': 'text/xml'
  },
  body: new XMLSerializer().serializeToString(transaction)
});

Работа с GeoServer

Наиболее частый сервер WFS — GeoServer. Он поддерживает:

  • WFS 1.0.0 / 1.1.0 / 2.0.0
  • CQL фильтры
  • Transaction (WFS-T)
  • Репроекция данных
  • Ограничение полей (propertyName)

Пример запроса с ограничением атрибутов:

propertyName=geom,name,type

Это уменьшает объём передаваемых данных.

Координатные системы и репроекция

WFS часто хранит данные в EPSG:4326, тогда как веб-карты используют EPSG:3857.

srsname=EPSG:3857

OpenLayers выполняет репроекцию автоматически при указании:

featureProjection: 'EPSG:3857'

Ошибки в CRS приводят к смещению объектов, что является одной из самых частых проблем при интеграции WFS.

Производительность и оптимизация

Работа с WFS требует контроля объёма данных:

  • ограничение через bbox
  • серверная фильтрация (cql_filter)
  • выборочное получение атрибутов (propertyName)
  • кэширование запросов
  • кластеризация точек (ol/source/Cluster)

Кластеризация:

import Cluster from 'ol/source/Cluster';

const clusterSource = new Cluster({
  distance: 40,
  source: vectorSource
});

Асинхронная загрузка и стратегия обновления

При изменении карты запросы WFS могут выполняться часто. Используются подходы:

  • debounce загрузки
  • отмена предыдущих запросов через AbortController
  • хранение загруженных экстентов
const controller = new AbortController();

fetch(url, { signal: controller.signal });
controller.abort();

Безопасность и CORS

WFS-запросы выполняются через HTTP, поэтому требуется:

  • настройка CORS на сервере
  • токены авторизации (Bearer, Basic Auth)
  • проксирование запросов через backend

Пример заголовка:

headers: {
  'Authorization': 'Bearer token'
}

Интеграция WFS с векторным слоем OpenLayers

Типовая архитектура слоя:

import VectorLayer from 'ol/layer/Vector';

const layer = new VectorLayer({
  source: source,
  style: styleFunction
});

Стилизация может зависеть от атрибутов WFS-объектов:

function styleFunction(feature) {
  const type = feature.get('type');

  return new Style({
    stroke: new Stroke({
      color: type === 'road' ? 'red' : 'blue'
    })
  });
}

Частые проблемы при работе с WFS

  • несоответствие CRS между сервером и клиентом
  • перегрузка сети из-за отсутствия bbox
  • медленные ответы GeoServer при больших выборках
  • некорректный GML namespace
  • отсутствие поддержки WFS-T на сервере
  • блокировка CORS при прямых запросах

Использование WFS в гибридных архитектурах

WFS часто комбинируется с другими источниками:

  • WMS для фоновой карты
  • WMTS для тайлов
  • WFS для интерактивных объектов
  • PostGIS как backend для GeoServer

Такая архитектура разделяет визуализацию и данные, снижая нагрузку на клиент.

Масштабируемые сценарии

При больших наборах данных применяется:

  • генерализация геометрии на сервере
  • уровни детализации (LOD)
  • тайлинг векторных данных (vector tiles как альтернатива WFS)
  • предварительная агрегация

WFS сохраняет актуальность в сценариях, где требуется точная геометрия и возможность редактирования, несмотря на появление более лёгких форматов передачи данных.