避免發生與安全性有關的 JavaScript 錯誤

Adobe AIR 1.0 以及更新的版本

如果您呼叫因為這些安全性限制而禁止在安全執行程序中使用的程式碼,執行階段便會傳送下列 JavaScript 錯誤:「應用程式安全執行程序中的 JavaScript 程式碼造成 Adobe AIR 執行階段安全性違規」。若要避免發生這個錯誤,請遵循下列程式碼做法。

與安全性有關的 JavaScript 錯誤發生原因

一旦引發文件的 load 事件,而且有任何 load 事件處理常式結束時,大部分涉及評估和執行字串的作業就會受到限制,無法在應用程式安全執行程序中執行程式碼。嘗試使用下列類型的 JavaScript 陳述式來評估和執行可能不安全的字串時,就會產生 JavaScript 錯誤:

將應用程式內容對應至不同的安全執行程序

在大部分情況下,您都可以重新撰寫應用程式或重新建立其架構,避免發生與安全性有關的 JavaScript 錯誤。不過,在無法重新撰寫或重新建立架構的情況下,您可以使用將應用程式內容載入至非應用程式安全執行程序中所述的技巧,將應用程式內容載入至不同的安全執行程序中。如果該項內容也必須存取 AIR API,您可以如設定安全執行程序橋接介面中所述,建立新的安全執行程序橋接。

eval() 函數

在應用程式安全執行程序中,eval() 函數只能在網頁的 load 事件傳送之前,以及在 load 事件處理常式執行期間使用。網頁完成載入之後,呼叫 eval() 將不會執行程式碼。不過,在下列情況中,您可以重新撰寫程式碼以避免使用 eval()

將屬性指定給物件

請不要透過下列所示方式剖析字串來建置屬性存取子:

eval("obj." + propName + " = " + val);

請改以方括號標記法來存取屬性:

obj[propName] = val;

使用可以在內容中使用的變數來建立函數

請將下列陳述式:

function compile(var1, var2){ 
    eval("var fn = function(){ this."+var1+"(var2) }"); 
    return fn; 
}

取代成為:

function compile(var1, var2){ 
    var self = this; 
    return function(){ self[var1](var2) }; 
}

使用類別名稱做為字串參數來建立物件

假設使用下列程式碼定義假設性的 JavaScript 類別:

var CustomClass =  
    { 
        Utils: 
        { 
            Parser: function(){ alert('constructor') } 
        }, 
        Data:  
        { 
         
        } 
    }; 
var constructorClassName = "CustomClass.Utils.Parser";

建立實體的最簡單方式,就是使用 eval()

var myObj; 
eval('myObj=new ' + constructorClassName +'()')

不過,您可以剖析該類別名稱的其中每一個字元,並使用方括號標記法建置新物件,以避免呼叫 eval()

function getter(str) 
{ 
    var obj = window; 
    var names = str.split('.'); 
    for(var i=0;i<names.length;i++){ 
        if(typeof obj[names[i]]=='undefined'){ 
            var undefstring = names[0]; 
            for(var j=1;j<=i;j++) 
                undefstring+="."+names[j]; 
            throw new Error(undefstring+" is undefined"); 
        } 
        obj = obj[names[i]]; 
    } 
    return obj; 
}

若要建立實體,請使用:

try{ 
    var Parser = getter(constructorClassName); 
    var a = new Parser(); 
    }catch(e){ 
        alert(e); 
}

setTimeout() 和 setInterval()

請以函數參考或物件取代傳遞做為處理常式函數的字串。例如,將下列陳述式:

setTimeout("alert('Timeout')", 100);

取代成為:

setTimeout(function(){alert('Timeout')}, 100); 

或者,當這個函數需要由呼叫者來設定 this 物件時,將下列陳述式:

this.appTimer = setInterval("obj.customFunction();", 100);

取代成為:

var _self = this; 
this.appTimer = setInterval(function(){obj.customFunction.apply(_self);}, 100);

Function 建構函式

new Function(param, body) 的呼叫可以取代為行內函數宣告,或者只在處理 load 事件之前使用這個呼叫。

javascript: URL

在應用程式安全執行程序中,使用 javascript: URL 配置在連結中定義的程式碼會遭忽略,這不會產生不安全的 JavaScript 錯誤。您可以將如下所示使用 javascript: URL 的連結:

<a href="javascript:code()">Click Me</a>

取代成為:

<a href="#" onclick="code()">Click Me</a>

在 innerHTML 和 outerHTML 陳述式中透過事件之特質指定的事件回呼

當您使用 innerHTML 或 outerHTML 將元素加入至文件的 DOM 時,所有在陳述式中指定的事件回呼 (例如 onclickonmouseover) 都會遭忽略,這不會產生安全性錯誤。您可以改為將 id 特質指定給這些新元素,並使用 addEventListener() 方法設定這些事件處理常式回呼函數。

舉例來說,您可以在文件中指定某個目標元素,如下所示:

<div id="container"></div>

將下列陳述式:

document.getElementById('container').innerHTML =  
    '<a href="#" onclick="code()">Click Me.</a>';

取代成為:

document.getElementById('container').innerHTML = '<a href="#" id="smith">Click Me.</a>'; 
document.getElementById('smith').addEventListener("click", function() { code(); });

載入位於應用程式安裝目錄以外的 JavaScript 檔案

您不可以載入位於應用程式安全執行程序以外的指令碼檔案,這不會產生安全性錯誤。在應用程式安全執行程序中執行的指令碼檔案都必須安裝在應用程式目錄內。若要在網頁中使用外部指令碼,您必須將該網頁對應至不同的安全執行程序。請參閱將應用程式內容載入至非應用程式安全執行程序

document.write() 和 document.writeln()

load 事件經過處理之後,對 document.write()document.writeln() 的呼叫會遭忽略,這不會產生安全性錯誤。此外,您也可以載入新的檔案,或使用各種 DOM 操作技巧來取代文件主體。

在 load 事件傳送之前或在 load 事件處理常式期間初始化的同步 XMLHttpRequest

在網頁的 load 事件傳送之前或在 load 事件處理常式執行期間初始化的同步 XMLHttpRequest 不會傳回任何內容。非同步 XMLHttpRequest 可以初始化,但是只有在傳送 load 事件之後才會傳回內容。在 load 事件經過處理之後,同步 XMLHttpRequest 便會正常運作。

動態建立的指令碼元素

動態建立 (例如建立時搭配 innerHTML 或 document.createElement() 方法) 的指令碼元素都會遭忽略。