一、問題描述:
在支持html5的瀏覽器中運行javascript腳本,腳本主要是操作網頁上的標簽canvas,出錯的操作為, getImageData(img,……),
chrome 下出錯信息為:"Unable to get image data from canvas because the canvas has been tainted by cross-origin data",
fireFox 下出錯信息為: "Security error" code: "1000"
關鍵代碼如下所示:
init:function(){ var img=new Image(); img.src="http://10.0.5.199:8080/hadoopWebGis2/jsp/map.jsp?img=0_0_0"; var ctx=this.context3D; img.onload=function(){ ctx.drawImage(img,0,0); var imgData=ctx.getImageData(0,0,img.width,img.height); //出錯行 ctx.putImageData(imgData,50,50); }; },
二、探索與解答
在網上搜索時發現大部分都說的是,getImageData這個函數,必須在服務器端運行,如果沒有服務器環境(比如,只是一個本地的 html網頁,操作本地的一張圖片),就會報"Unable to get image data from canvas because the canvas has been tainted by cross-origin data"錯誤。
但是很明顯的,我上面的示例程序是運行在一個 tomcat服務器中的,仍然報了這個錯誤。那么這個問題到底是怎么回事呢?
后來在stackoverflow上找到了問題的原因。(強烈推薦stackoverflow網站,這是一個非常著名的技術問答網站,涵蓋的范圍非常廣,包括C、C++、java、web、linux等各方面。中國學生大多不喜歡看英文網頁,但事實上,很多問題,中文網頁看一大堆也沒有辦法,在很多優秀的英文網站,如stackoverflow上卻能很快找到答案。)
下面是stackoverflow上對該問題的一個回答:
翻譯如下:為了阻止欺騙,瀏覽器會追蹤 image data。當你把一個“跟canvas的域不同的”圖片放到canvas上,這個canvas就成為 “tainted”(被污染的,臟的),瀏覽器就不讓你操作該canvas 的任何像素。這對於阻止多種類型的XSS/CSRF攻擊(兩種典型的跨站攻擊)是非常有用的。
上面的話中關鍵點在於紅色標記出的文字“跟canvas的域不同的”, 於是我查看了我的圖片請求與網頁請求的地址,發現它們的域果然是不同的,
圖片請求地址:http://10.0.5.199:8080/hadoopWebGis2/jsp/map.jsp?img=0_0_0 輸入瀏覽器中的網頁的地止為:http://summer1:8080/hadoopWebGis2/jsp/map3D.html
(雖然在hosts文件中配置的影射為:10.0.5.199:summer1,按理說會瀏覽器會自動對兩者進行轉換的,卻不知為什么,還是識別成了不同的域。)
修改為如下后,問題解決:
圖片請求地址:http://summer1:8080/hadoopWebGis2/jsp/map.jsp?img=0_0_0 輸入瀏覽器中的網頁的地止為:http://summer1:8080/hadoopWebGis2/jsp/map3D.html -----------------或者------------------------- 圖片請求地址:http://10.0.5.199:8080/hadoopWebGis2/jsp/map.jsp?img=0_0_0 輸入瀏覽器中的網頁的地止為:http://10.0.5.199:8080/hadoopWebGis2/jsp/map3D.html
---------------------------------------------------------------------------------------------------------------------------------------------------------
題外話:為什么沒有服務器環境(比如,只是一個本地的 html網頁,操作本地的一張圖片),就會報"Unable to get image data from canvas because the canvas has been tainted by cross-origin data"錯誤 ?
個人理解:本地網頁的域為file://,如:file:///home/summer/Desktop/test.html ,而本地圖片肯定不是以file://開頭的,如linux環境下的某個圖片為:/home/summer/Desktop/test.png,windows環境下的某個圖片為: c:\tmp\test.png。