canvas 跨域問題
如果canvas中所繪制的Image或者資源有跨域,則對canvas中的數據進行操作往往會報錯,例如在地圖導出或者操作像素時
Uncaught DOMException: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data.
canvas的CanvasRenderingContext2D屬于瀏覽器中的對象,如果曾經渲染過跨域資源。 瀏覽器就認定canvas已經被污染(tainted)了。問題很常見,所以可以對canvas所加載的資源,特別是圖片設置跨域,
image.crossOrigin="anonymous";
對image對象的crossOrigin屬性設置anonymous,那么在image.src= "http://some.com/demo.jpg" 的時候,發送的GET請求,到達對方服務器some.com,如果碰巧對方服務器對這類資源的不限制訪問,也就是response header的 Access-Control-Allow-Origin 字段為 "*" ,那么我們的瀏覽器可成功獲取資源。
Access-Control-Allow-Origin 這個response header 很常用,確保了服務器對資源的跨域限制。如果需要限定白名單,就直接把白名單的domain或者ip放到value 中。 關于Ol3的切片跨域問題,公瑾大神在這篇文章中已經說得很清楚了,不再贅述
請求有跨域限制的服務器資源
但如果對方服務器限制跨域訪問,那不論咱們的前端代碼如何設定,都無法繞開。最好的辦法之一就是后端代理,DEMO ,點左邊這個鏈接可以在線體驗下。。(切片走的代理,另外隨便輸入個公交線路數字,也是走后臺代理的)
在前端需要請求跨域資源時,給URL加上同域下的后臺代理前綴,讓這個請求走代理轉發一下。。真心是老技術。所以隨便寫寫,不花心思完善了。以Nodejs為例的寫了一個后臺代理模塊,主要內容如下:
var Proxy = function (req, res) {
// proxy the client request.
(function() {
console.log("receive client req : "+ req.query['proxyURI']);
var target = req.query['proxyURI'];
// thisPlace should first check localFile if exists, res localFile directly.. 這邊呢,接收到前端的請求,把實際要請求的地址拿到,后臺轉發。
http.get(target, function(response) {
console.log("Proxy got response: " + response.statusCode);
var resContentType = response.headers["content-type"];
res.setHeader("Content-Type", resContentType);
var buffer = [];
response.on('data', (chunk) => {
buffer.push(chunk);
});
response.on('end', () => {
// Buffer toString. 'ascii'/'base64'
var buff = Buffer.concat(buffer);
for(var k in strategies) {
if (resContentType.indexOf(k) > -1) {
// ready to save buffer to localFile.. 碰到策略中指定的文件類型,在本地緩存下
try {
var ext = resContentType.split("/")[1];
var tmpArr = target.split("/");
var fileName = tmpArr[tmpArr.length-2] + "_" + tmpArr[tmpArr.length-1] + "." + ext;
var finalName = "./Asset/tiles/" + fileName;
fs.exists(finalName, function(exists) {
if (exists) {
// 如果這個文件本地緩存過了,直接發回前端。
res.sendFile(finalName, {
root: __dirname
});
} else {
fs.writeFileSync("./Asset/tiles/" + fileName, buff);
res.sendFile(finalName, {
root: __dirname
});
}
});
return;
} catch (error) {
console.error("proxyImage error.");
res.end("proxyImage error.");
}
}
}
// 非二進制文件類型(JSON,HTML等),直接發回字符串
res.end(buff.toString());
});
}).on('error', function(e) {
console.error("Proxy got error: " + e.message);
});
})()
}
module.exports = Proxy;
我記得openlayer2的時候官方有贈送一個python版本的代理,現在ol3好像沒了。所以突然發現這個代理還有:
切片下載的功能!! \(o)/,后臺會隨著前端的請求過程,緩存圖片等文件。
一起搞項目
這個代理模塊拿來改改參數就可以勉強用了。所以需要的弟兄們直接去 Github項目地址 取用即可
這個項目是最近比較常用的,包括了平日里做的一些小插件和DEMO之類的。比如:
- Openlayer-實現帶碰撞檢測的標注
- 基于canvas的部分模糊插件, DEMO ,簡單封裝了個Blurify類,配置可用
- 基于Ol2和Jquery Mobile的移動端APP ,這個比較早期
還有另外一個ThreeJS項目有空也在弄,其實想基于ES6做一些模塊化的ThreeJS開發,用于搭建三維游戲場景。之前代碼寫得比較隨意,現在必須模塊化,不然沒法看。。先來個DEMO瞅瞅,數據量大多等會兒,鼠標右鍵拖動場景。
希望有人一起搞啊,很有趣的項目。。。