OpenLayers3關於Map Export的Canvas跨域

weixin_33936401發表於2016-12-07

一 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() });

沒多寫一行程式碼的飄逸,抄過來直接執行,報錯如下:


68979-fca438ecf71c0027.png
跨域錯誤.png

二 問題排查

檢查案例原始碼發現和我抄襲的程式碼幾乎一模一樣,唯一區別是我使用的是谷歌底圖,例子使用的是osm的source。

 new ol.layer.Tile({ source: new ol.source.OSM() }),

為了一看究竟,我們檢視osm的source原始碼如下:

68979-790d9bf66ef5b07f.png
osm souce原始碼

恍然大悟,原來只需要新增這 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!

相關文章