WMS 与 WMTS 服务接入
内网 GIS 平台的底图和专题图多数以 OGC 服务发布。 WMS 按范围出图,WMTS 按瓦片编号取图,两者参数结构不同,接错的表现也很不一样。
WMS:按请求范围返回一张图
WMS 的核心是 GetMap 请求,客户端把当前视野的地理范围发给服务端,
服务端实时渲染一张图片返回。参数里最重要的是图层名和版本:
var wmsLayer = new ol.layer.Tile({
source: new ol.source.TileWMS({
url: 'https://demo.mapserver.org/cgi-bin/wms',
params: {
'LAYERS': 'bluemarble', // 图层名,多个用逗号分隔
'VERSION': '1.1.1'
},
serverType: 'mapserver',
crossOrigin: 'anonymous'
})
});
TileWMS 把大范围切成 256 像素的小请求,
服务端支持 TILED=true 时命中缓存;不支持时每个瓦片都是独立渲染,
拼缝处会出现线状断裂。不能确认服务是否支持时,可以改用
ol.source.ImageWMS,一次只请求一张覆盖视野的图:
var imageLayer = new ol.layer.Image({
source: new ol.source.ImageWMS({
url: 'https://example.gov.cn/geoserver/plan/wms',
params: { 'LAYERS': 'plan:parcels', 'VERSION': '1.1.1' },
ratio: 1.1 // 多取 10% 范围,减弱拖动时的边缘空白
})
});
常用请求参数
| 参数 | 作用 | 常见取值 |
|---|---|---|
LAYERS | 要渲染的图层 | 工作区名前缀不可省,如 plan:parcels |
STYLES | 服务端样式名 | 空字符串表示默认样式 |
VERSION | 协议版本 | 1.1.1 或 1.3.0 |
FORMAT | 返回图片格式 | image/png 支持透明 |
TRANSPARENT | 背景透明 | 叠加在底图上必须为 true |
TILED | 按瓦片请求 | GeoServer 支持,MapServer 不支持 |
这些参数都写在 params 对象里,键名大小写要与服务端约定一致。
OpenLayers 会自动追加 SERVICE=WMS、REQUEST=GetMap、
BBOX、WIDTH、HEIGHT、SRS 等必需项,
不需要手写。
1.3.0 版本的坑:WMS 1.3.0 在 EPSG:4326 下把坐标轴顺序定为
纬度在前,部分服务端严格遵循,导致返回的图上下颠倒或左右错位。
遇到这种服务,把 VERSION 固定为 1.1.1,
或改用 EPSG:3857 请求。
叠加到已有底图上
专题图通常叠在底图之上,需要满足三个条件:
专题层的 TRANSPARENT 为 true、
FORMAT 为 image/png、
服务端支持与视图一致的坐标系。
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({ source: new ol.source.OSM() }),
new ol.layer.Tile({
source: new ol.source.TileWMS({
url: 'https://example.gov.cn/geoserver/plan/wms',
params: {
'LAYERS': 'plan:roads',
'VERSION': '1.1.1',
'FORMAT': 'image/png',
'TRANSPARENT': true
},
transition: 0
}),
opacity: 0.8
})
],
view: new ol.View({
center: ol.proj.fromLonLat([116.391263, 39.907359]),
zoom: 12
})
});
transition: 0 关闭瓦片淡入,专题图在缩放时不会出现半透明闪烁。
WMTS:按瓦片矩阵取图
WMTS 是瓦片服务,请求里带 TILEMATRIX、TILECOL、
TILEROW,客户端必须事先知道服务的瓦片矩阵集。
先看 GetCapabilities,确认 TileMatrixSet 名称和
每一级的 ScaleDenominator、TopLeftCorner。
var projection = ol.proj.get('EPSG:3857');
var projectionExtent = projection.getExtent();
var size = ol.extent.getWidth(projectionExtent) / 256;
var resolutions = [];
var matrixIds = [];
for (var z = 0; z < 18; z++) {
resolutions[z] = size / Math.pow(2, z);
matrixIds[z] = z; // 部分服务是 'EPSG:3857:0' 这种格式
}
var wmtsLayer = new ol.layer.Tile({
source: new ol.source.WMTS({
url: 'https://example.gov.cn/wmts',
layer: 'img',
matrixSet: 'EPSG:3857',
format: 'image/png',
style: 'default',
projection: projection,
tileGrid: new ol.tilegrid.WMTS({
origin: ol.extent.getTopLeft(projectionExtent),
resolutions: resolutions,
matrixIds: matrixIds
}),
wrapX: true
})
});
matrixIds 必须与服务端完全一致。天地图、ArcGIS Server、
GeoServer 三家的命名规则都不同,常见的还有
'EPSG:3857:0'、'0'、'GoogleMapsCompatible:0'。
填错时控制台会大量 404,地图一片空白。
RESTful 风格的 WMTS
有些服务把参数拼在路径里,而不是查询串。
把 requestEncoding 设为 'REST',
并在 url 中用花括号占位:
new ol.source.WMTS({
url: 'https://example.gov.cn/wmts/1.0.0/{Layer}/{Style}/{TileMatrixSet}/{TileMatrix}/{TileRow}/{TileCol}.png',
requestEncoding: 'REST',
layer: 'img',
style: 'default',
matrixSet: 'EPSG:3857',
format: 'image/png',
projection: projection,
tileGrid: tileGrid
});
跨域与图片导出
服务端没有返回 Access-Control-Allow-Origin 时,
瓦片能显示,但 canvas 会被标记为“污染”,
导出图片、截图、像素命中测试全部失败,控制台报
Tainted canvases may not be exported。
解决方式是在数据源上声明 crossOrigin: 'anonymous',
同时要求服务端开启 CORS。两者缺一不可:
客户端声明了但服务端没开,瓦片直接加载失败;服务端开了客户端没声明,画布依然被污染。
白图与错位的排查顺序
| 现象 | 先查什么 | 处理 |
|---|---|---|
| 整张白图,控制台 404 | 图层名、工作区前缀、URL 路径 | 用浏览器直接打开 GetCapabilities 核对 |
| 返回的是异常 XML | 服务端报错信息 | 看 ServiceException 文本,多为图层名或 CRS 不支持 |
| 图有内容但整体偏移 | 服务端声明的 CRS 与视图是否一致 | 统一投影,或让服务端加 SRS=EPSG:3857 |
| 图上下颠倒 | 是否为 WMS 1.3.0 + 4326 | 降级到 1.1.1 |
| 缩放时闪烁、断层 | 是否开启 TILED、transition | 关掉 TILED 或设 transition: 0 |
| 瓦片 404 但服务正常 | matrixIds 命名 | 按 Capabilities 里的 TileMatrix 标识逐级写 |
调试捷径:在浏览器网络面板里复制一条失败的 GetMap 请求,
贴到地址栏直接访问。如果返回的是 XML 而不是图片,
错误原因就写在 XML 的 ServiceException 节点里。
经纬志(2026)。《WMS 与 WMTS 服务接入》。https://www.jingweizhi.com/openlayers/tutorial/wms-wmts.html(访问日期 2026-11-03)。