一 Canvas跨域现象
地图导出是地图中常用的功能,并且OpenLayers3中也提供了两个地图导出的例子:
http://openlayers.org/en/latest/examples/export-map.html http://openlayers.org/en/latest/examples/export-pdf.html。
看到这两个例子我们都很兴奋,直接copy过来不就实现导出地图了吗?so easy,妈妈再也不用担心我导出不了地图图片啦!
但当我们抄好代码执行时,现实就是这么赤裸裸的打脸:
我的代码如下:
//街道图
Layer.streetLayer=new ol.layer.Tile({
source: new ol.source.XYZ({
url: 'http://www.google.cn/maps/vt?pb=!1m5!1m4!1i{z}!2i{x}!3i{y}!4i256!2m3!1e0!2sm!3i342009817!3m9!2szh-CN!3sCN!5e18!12m1!1e47!12m3!1e37!2m1!1ssmartmaps!4e0&token=32965'
})
});
例子的图层代码如下:
layer=new ol.layer.Tile({ source: new ol.source.OSM() });
没多写一行代码的飘逸,抄过来直接运行,报错如下:
二 问题排查
检查案例源码发现和我抄袭的代码几乎一模一样,唯一区别是我使用的是谷歌底图,例子使用的是osm的source。
new ol.layer.Tile({ source: new ol.source.OSM() }),
为了一看究竟,我们查看osm的source源码如下:
恍然大悟,原来只需要添加这 crossOrigin:'anonymous'就可以了。
于是改写重置自己的谷歌图层代码如下:
//街道图
Layer.streetLayer=new ol.layer.Tile({
source: new ol.source.XYZ({
crossOrigin: 'anonymous',
url: 'http://www.google.cn/maps/vt?pb=!1m5!1m4!1i{z}!2i{x}!3i{y}!4i256!2m3!1e0!2sm!3i342009817!3m9!2szh-CN!3sCN!5e18!12m1!1e47!12m3!1e37!2m1!1ssmartmaps!4e0&token=32965'
})
});
这下打印正常了。
三 加载自己的wms底图还是跨域错误
我们上面通过对谷歌地图加crossOrigin: 'anonymous'实现了地图输出了,解决canvas跨域问题了,但一般我们地图是底图+业务底图(如wms)的,这时候打印发现还是报错。
Layer.streetLayer=new ol.layer.Tile({
source: new ol.source.XYZ({
crossOrigin: 'anonymous',
url: 'http://www.google.cn/maps/vt?pb=!1m5!1m4!1i{z}!2i{x}!3i{y}!4i256!2m3!1e0!2sm!3i342009817!3m9!2szh-CN!3sCN!5e18!12m1!1e47!12m3!1e37!2m1!1ssmartmaps!4e0&token=32965'
})
});
Layer.wmsship = new ol.layer.Tile({
source: new ol.source.TileWMS({
url: geoserverhost+'/gwc/service/wms',
params: {'FORMAT': 'image/png',
'VERSION': '1.1.1',
tiled: true,
STYLES: '',
LAYERS: 'ships:ta_pos_latest'
}
})
});
这个例子我们使用了谷歌底图叠加自己的wms/gwc等瓦片图,发现export还是报跨域错误,理所当让的,我给Layer.wmsship设置crossOrigin: 'anonymous',以为就可以了,但不幸的是仍然报跨域错误,一点没反应。
四 设置服务器cors彻底解决
我们发现,谷歌,osm设置crossOrigin就可以,我们自己wms设置的crossOrigin还是不行。问题出在哪里咧?查阅资料可知,osm,google的服务器一定设置了cors,所以客户端设置crossOrigin才会起作用,而我们自己的wms或者瓦片所在的服务器没有设置cors,所以客户端设置或者不设置crossOrigin,都是无效的。也就是说,只有自己的服务器设置了cors,crossOrigin才会起到作用。
我们地图是geoserver发布的wms或者gwc,对geoserver设置cors,参考之前的博客:http://blog.csdn.net/freeland1/article/details/41204485 ,根据第三节的cors设置下自己的服务器。
服务器设置完毕后,代码改为如下
Layer.streetLayer=new ol.layer.Tile({
visible: true,
source: new ol.source.XYZ({
crossOrigin: 'anonymous',
url: 'http://www.google.cn/maps/vt?pb=!1m5!1m4!1i{z}!2i{x}!3i{y}!4i256!2m3!1e0!2sm!3i342009817!3m9!2szh-CN!3sCN!5e18!12m1!1e47!12m3!1e37!2m1!1ssmartmaps!4e0&token=32965'
})
});
Layer.wmsship = new ol.layer.Tile({
source: new ol.source.TileWMS({
crossOrigin: 'anonymous',
url: geoserverhost+'/gwc/service/wms',
params: {'FORMAT': 'image/png',
'VERSION': '1.1.1',
tiled: true,
STYLES: '',
LAYERS: 'ships:ta_pos_latest'
}
})
});
地图输出终于不报错了,perfect!