小编典典

返回JavaScript代码时如何在PHP / Dojo中正确生成异常

ajax

我很难理解通过AJAX动态获取代码并通过执行代码时如何处理异常eval。使用客户端javascript,如果我有一段这样的代码,这相当简单

var j = 'some string';
j.propA.x++;

这将引发异常,因为propA类型为的undefined没有x。此外,引发的异常非常容易理解。

现在,将上面的代码放入一个文本文件中,进行调用test.js,并将其存储在服务器上。现在让我们使用Ajax动态加载它。我正在使用以下代码动态加载它

dojo.xhrGet({
  url: 'load.php',
  handleAs: "javascript",
  content : {
    fileName : 'test.js'
  },
  load: function(returnValue) {
    /*Do Something*/
  },
  error: function(errorMessage) {
    /*Report Error*/
  }
});

这是一个非常基本的php脚本,用于加载文件并将其作为javascript代码返回

<?php
  $fileName = $_GET['fileName'];
  $handle = fopen($fileName , 'r');
  $script = fread($handle, filesize($fileName));
  fclose($handle);
  echo $script;
?>

在上面的dojo.xhrGet调用中,error可以将属性设置为显示错误消息的函数,这是可以完成此操作的一些示例。

error: function(errorMessage) {
  console.error(errorMessage);
  console.error(errorMessage.arguments);
  console.error(errorMessage.message);
  console.error(errorMessage.stack);
  console.error(errorMessage.type);
}

以下是输出示例。尽管此输出是针对另一个问题的,但它突出了它的不可理解性:

Cannot read property 'x' of undefined
TypeError: Cannot read property 'x' of undefined
    at eval at <anonymous> (http://o.aolcdn.com/dojo/1.6/dojo/dojo.xd.js:14:3088)
    at Object.load (http://192.168.1.8/easel.js:166:6)
    at http://o.aolcdn.com/dojo/1.6/dojo/dojo.xd.js:14:89998
    at _144 (http://o.aolcdn.com/dojo/1.6/dojo/dojo.xd.js:14:36518)
    at _142 (http://o.aolcdn.com/dojo/1.6/dojo/dojo.xd.js:14:36328)
    at [object Object].<anonymous> (http://o.aolcdn.com/dojo/1.6/dojo/dojo.xd.js:14:36994)
    at _144 (http://o.aolcdn.com/dojo/1.6/dojo/dojo.xd.js:14:36780)
    at _142 (http://o.aolcdn.com/dojo/1.6/dojo/dojo.xd.js:14:36328)
    at [object Object].<anonymous> (http://o.aolcdn.com/dojo/1.6/dojo/dojo.xd.js:14:36994)
    at Object.resHandle (http://o.aolcdn.com/dojo/1.6/dojo/dojo.xd.js:14:92730)
non_object_property_load

我假设这dojo.xd.js:14eval语句所在的行。

如果知道他们在寻找什么,上面的内容就足够了。但是,是否存在一种更简单或更有效的方式来处理出现的异常eval


是一个有点类似的问题。


菲金在下面为这个问题提供了很好的解决方案,所以我给了他赏金。使用他的解决方案,我得到的输出看起来像这样(我将其削减了一点)

    ReferenceError in JS Code detected: (url: module.require.php?module=MainMenu.Bg_S)
easel.js:211Error Message: ReferenceError: apple is not defined
easel.js:213(function(){
return function(args){
dojo.require("Shape");

Module.assert('MainMenu_V');

/**
* The rectangular background of the Main View
* @property MainMenuBg_S
* @type Shape
**/
new Shape({
    /**
    * Unique descriptive name used when later accessing this shape via '$$()'
    * @param name
    * @type String
    **/
    name : 'MainMenu.Bg_S' , 
    /**
    * Left side of this rectangle
    * @param x
    * @type Number
    **/             
    x : $$('MainMenu_V').x ,

    /**
    * Top of this rectangle
    * @param y
    * @type Number
    **/ 
    y : $$('MainMenu_V').y ,

    /**
    * Width of this rectangle
    * @param w
    * @type Number
    **/ 
    w : $$('MainMenu_V').w ,

    /**
    * Height of this rectangle
    * @param h
    * @type Number
    **/ 
    h : $$('MainMenu_V').h ,

    /**
    * Type of this Shape
    * @param h
    * @type Number
    **/ 
    type : shapeType.RECTANGLE ,

    /**
    * Generate function which contains all the graphics instructions, as well as the contexts
    * to preload and initialize. This is currently under development. Backgrounds should NEVER
    * have mouse events associated with them as a redraw of a background implies a redraw of 
    * every single displayObject infront of the background.
    * @param generate
    * @type method
    **/   
    generate : function (){
        var x = this.x << 0 , y = this.y << 0 , h = this.h << 0 , w = this.w << 0 , a = this.a;

        this.graphics(contextID.LEAVE).lf([hsl(180,100,60,0.9),hsl(180,100,20,0.75)],[0,1],0,h/2,w,h/2).dr(x,y,w,h).ef();
        this.graphics(contextID.ENTER).lf([hsl(135,100,40,0.9),hsl(135,100,20,0.75)],[0,1],0,h/2,w,h/2).dr(x,y,w,h).ef();
        this.graphics(contextID.CLICK).lf([hsl(90,100,40,0.9),hsl(90,50,20,0.75)],[0,1],0,h/2,w,h/2).dr(x,y,w,h).ef();
        this.graphics(contextID.RCLICK).lf([hsl(90,110,40,0.9),hsl(80,60,20,0.45)],[0,1],0,h/2,w,h/2).dr(x,y,w,h).ef();
        this.graphics(contextID.DBLCLICK).lf([hsl(45,100,40,0.9),hsl(45,100,20,0.75)],[0,1],0,h/2,w,h/2).dr(x,y,w,h).ef();
        this.graphics(contextID.DBLRCLICK).lf([hsl(10,100,40,0.9),hsl(10,100,20,0.75)],[0,1],0,h/2,w,h/2).dr(x,y,w,h).ef();
        this.graphics(contextID.LPRESS).lf([hsl(110,25,40,0.9),hsl(110,25,20,0.75)],[0,1],0,h/2,w,h/2).dr(x,y,w,h).ef();
        this.graphics(contextID.RPRESS).lf([hsl(110,50,40,0.9),hsl(110,50,20,0.75)],[0,1],0,h/2,w,h/2).dr(x,y,w,h).ef();
        this.graphics(contextID.SCROLL).lf([hsl(110,50,40,0.9),hsl(110,50,20,0.75)],[0,1],0,h/2,w,h/2).dr(x,y,w,h).ef();

        if (debugFlags.BOUNDINGBOX()){
            this.graphics(contextID.ENTER).ss(2).s(rgba(0,255,0,a)).dr(this.boundingBox.softBounds.L +4<<0, this.boundingBox.softBounds.T +4<<0, this.boundingBox.softBounds.w-8<<0 , this.boundingBox.softBounds.h-8<<0).es();
            this.graphics(contextID.ENTER).ss(2).s(rgba(255,0,0,a)).dr(this.boundingBox.bounds.L +4<<0, this.boundingBox.bounds.T +4<<0, this.boundingBox.bounds.w-8<<0 , this.boundingBox.bounds.h-8<<0).es();
            this.graphics(contextID.ENTER).f(rgba(0,0,255,a)).dc(this.boundingBox.points[0].x+4 , this.boundingBox.points[0].y+4 , 4).ef();
            this.graphics(contextID.ENTER).f(rgba(0,0,255,a)).dc(this.boundingBox.points[1].x-8 , this.boundingBox.points[1].y+4 , 4).ef();
            this.graphics(contextID.ENTER).f(rgba(0,0,255,a)).dc(this.boundingBox.points[2].x-8 , this.boundingBox.points[2].y-8 , 4).ef();
            this.graphics(contextID.ENTER).f(rgba(0,0,255,a)).dc(this.boundingBox.points[3].x+4 , this.boundingBox.points[3].y-8 , 4).ef();
        }
    },

    /**
    * Arguments to pass to the mouse initialization function. These will get mixed in (via
    * dojo.mixin) to the mouse object. To increase performance, the signalOrderIn has been set to
    * NOHIT. This will limit the number of redraws (remember background redraws are extremely
    * expensive as they require redrawing everything in the container). The signalOrderOut is 
    * then set to BLOCK to prvent anything behind the background from receiving mouse signals
    * (this is actually unecessary as the only think behind the background is, and always should
    * be, the container, which itself has signalOrderIn and signalOrderOut set to NOHIT and BLOCK
    * respectively).
    * @param mouse
    * @type Object
    **/ 
    mouse : {
        _signalOrderIN : signalFlags.NOHIT ,
        _signalOrderOUT : signalFlags.BLOCK
    } ,

    /** 
    * All views are initially loaded via Ajax. Generally, views do not have any preconditions, beyond
    * that the stage be present. They can, however, and generally do, have modules they require. These
    * are called after this view has been created and loaded (load() function call). They are called
    * in the order of the sub arrays. In the example below:
    * [[A , B , C , D , E , F , G]]
    * The 7 modules are requested in that order, but, due to Ajax, they can be loaded in any order. 
    * In the below example, on the other hand:
    * [[A] , [B , C , D , E , F , G]]
    * Modules B-G depend on module A, therefore, module A is ordered to be loaded first. 
    * @property providedModules
    * @type Array[Array[String]]
    * @protected
    **/
    providedModules : [[]] ,

    /** 
    * Carries out all the initializations when loading the module
    * @method load
    * @protected
    **/
    load : function (){
                0/apple;
        $$('MainMenu_V').addChild(this);
    } ,

    /** 
    * Carries out all memory deallocation when leaving the module (generally only necessary if modules
    * were loaded but not added to stage as in the case with cached bitmaps)
    * @method leave
    * @protected
    **/
    leave : function (){
    }
});
$$('MainMenu.Bg_S')._code="dojo.require(\"Shape\");...";
};
}());

easel.js:217Error triggered by: function (_2bd){return err.call(args,_2bd,_2b7);}
easel.js:220XHR Object:
easel.js:221
Object
args: Object
handleAs: "javascript"
query: null
url: "module.require.php?module=MainMenu.Bg_S"
xhr: XMLHttpRequest
__proto__: Object
easel.js:222Error Object:
easel.js:223
ReferenceError
arguments: Array[1]
message: "—"
stack: "—"
type: "not_defined"
__proto__: Error
dojo.xd.js:14
ReferenceError
arguments: Array[1]
message: "—"
stack: "—"
type: "not_defined"
__proto__: Error
dojo.xd.js:14
ReferenceError
arguments: Array[1]
message: "—"
stack: "—"
type: "not_defined"
__proto__: Error

我唯一需要缺少的是能够指出问题发生在哪一行。


阅读 242

收藏
2020-07-26

共1个答案

小编典典

这是一个片段,可从xhr-get请求中检测与网络无关的错误,并在控制台中输出有关此错误的一些信息。

还有一个额外的isEvalError()函数可以处理所有eval-
error类型……我并不为此感到骄傲。更好的方法是获取errorMessage子类的父对象。我认为您通常可以放弃isEvalError(),因为在此块中不应有任何其他错误。

function isEvalError(errorMessage){
    return errorMessage.name == "RangeError" ||
    errorMessage.name == "ReferenceError" ||
    errorMessage.name == "SyntaxError" ||
    errorMessage.name == "URIError" ||
    errorMessage.name == "TypeError";
}

var foo = dojo.xhrGet({
    url: 'stacko.js',
    handleAs: "javascript",
    load: function(returnValue) {
        console.log("load: "+returnValue);
    },
    error: function(errorMessage,ioargs) {

        //request worked fine, this must be a non-network related error
        if(ioargs.xhr.readyState == 4 && ioargs.xhr.status == 200) {


            if(isEvalError(errorMessage)){
                //show eval-error, url request & the JS code that causes the exception
                //eval-error types: RangeError,ReferenceError,SyntaxError, URIError, TypeError
                console.error(errorMessage.name+" in JS Code detected: (url: "+ioargs.url+")")
                console.error("Error Message: "+ errorMessage);

                console.error(ioargs.xhr.responseText);
            }

            //a little reflection - if u want to know who triggered this error 
            //(although in this case the output is not very helpful )
            console.error("Error triggered by: "+arguments.callee.caller.toString());

            //last but not least log the error & the xhr-request object for more information
            console.error("XHR Object:");
            console.error(ioargs);
            console.error("Error Object:");
            console.error(errorMessage);


        }


    }
});
2020-07-26