如何 jQuery Ajax 错误捕获和报告

How to jQuery Ajax Error Catch and Report

js报错产生的ajaxerror事件的函数调用者通过什么方式获取?

我用 jQuery 构建了一个 js 错误 repo 应用程序,我可以处理全局发生的正常 js 错误,但我在 ajax 错误方面遇到问题。 当是正常错误时我可以得到错误的行号! 我试图用全局 ajax 处理程序 "ajax error" 之一来捕获它们,但我不确定如何获取该 ajax 调用者或调用者姓名的行号。

请看底部!

const error_log_url = '/log';
const errorPost = function (data) {
    $.ajax({
         url: error_log_url,
         type: 'post',
         data: data,
         success: function (res) {
             console.log(res)
         }, error: function (res) {
            console.log(res)
         }
     })
 }
 window.addEventListener('error', function (e) {

     let params = {
         message: e.message || "Exception Handler",
         url: e.filename || "",
         lineno: e.lineno || 0,
         colno: e.colno || 0
     }

     errorPost(params)
 }, true);

 // wrap function for new error stack with adding event to certain element
 window.wrap = function (func) {
    // make sure you only wrap the function once
    if (!func._wrapped) {
        func._wrapped = function () {
            try {
                func.apply(this, arguments);
            } catch (exception) {
                throw exception
            }
        }
    }
    return func._wrapped;
 }

 // override add & remove event listeners with above wrap function
 let addEvenListener = window.EventTarget.prototype.addEventListener;
 window.EventTarget.prototype.addEventListener = function (event, callback, bubble) {
    addEvenListener.call(this, event, wrap(callback), bubble);
 }

 let removeEventLister = window.EventTarget.prototype.removeEventListener;
 window.EventTarget.prototype.removeEventListener = function (event, callback, bubble) {
    removeEventLister.call(this, event, callback._wrapped || callback, bubble);
 }

 $(document).ajaxError(function( event, jqxhr, settings, thrownError ) {

     // please look at here, how can I get the caller name that produced this error!
     console.log(arguments.callee.caller)

     if (settings.url != error_log_url)
         errorPost({
             message: event.type,
             filename: event.currentTarget.location.origin + settings.url
         })


 });

console.log(arguments.callee.caller) 这会打印出 null。

你看,我可以从 ErrorEvent 中获取更多信息,但我无法从 ajaxError 事件中获取行号等详细信息!

不幸的是,似乎有 no global event 网络错误。

虽然有一个 hacky 方法可以解决这个问题 - 如果您将一个函数附加到 ajaxSend 方法,该方法在发送请求时运行,您可以立即抛出错误 ,然后捕获它并检查堆栈以找出调用者。然后,将适当的堆栈行放入 WeakMap 中,稍后可以检查,由 jqXHR 对象索引。之后,如果请求失败,在 ajaxError 处理程序中,使用其 jqXHR 对象在 WeakMap 中查找堆栈。例如:

$(document).ajaxError(function(event, jqxhr, settings, thrownError) {
  console.log(stacksByXHR.get(jqxhr));
});
const stacksByXHR = new WeakMap();
$(document).ajaxSend((event, jqXHR) => {
  try {
    throw new Error();
  } catch({ stack }) {
    let callCountNonJquery = 0;
    const foundCall = stack
      .split('\n')
      .slice(1) // Remove the top "Error" line, contains no information
      .find(line => {
        if (line.includes('jquery')) {
          return false;
        }
        callCountNonJquery++;
        // First call would be the thrown error above
        // Second call is the $.ajax initiator
        if (callCountNonJquery === 2) {
          return true;
        }
      });
    stacksByXHR.set(jqXHR, foundCall);
  }
});
$.ajax('/DoesNotExist');
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

在我的机器上,这显示了我

at https://stacksnippets.net/js:40:3

对应于$.ajax('/DoesNotExist');行:

如果$.ajax在函数内部,函数名也会在栈中可见,例如:

$(document).ajaxError(function(event, jqxhr, settings, thrownError) {
  console.log(stacksByXHR.get(jqxhr));
});
const stacksByXHR = new WeakMap();
$(document).ajaxSend((event, jqXHR) => {
  try {
    throw new Error();
  } catch({ stack }) {
    let callCountNonJquery = 0;
    const foundCall = stack
      .split('\n')
      .slice(1) // Remove the top "Error" line, contains no information
      .find(line => {
        if (line.includes('jquery')) {
          return false;
        }
        callCountNonJquery++;
        // First call would be the thrown error above
        // Second call is the $.ajax initiator
        if (callCountNonJquery === 2) {
          return true;
        }
      });
    stacksByXHR.set(jqXHR, foundCall);
  }
});
function myFunctionWhichRunsAjax() {
  $.ajax('/DoesNotExist');
}
myFunctionWhichRunsAjax();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>