我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

需求是这样的,希望抛出一个自定义错误。但是,不想暴露任何的调试信息。比如:在网络接口服务中,throw了一个new Error()。这个时候,就是单纯的错误发生在第几行第几列,错误信息的堆栈是怎样的。因为这个属于网络接口,存在非法访问的可能性。所以,这些对于报错堆栈信息,就存在着信息安全风险。

苏南大叔:JavaScript,如何抛出一个不带堆栈调试信息的error? - 不带stack信息的error
JavaScript,如何抛出一个不带堆栈调试信息的error?(图4-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔的编程经验文章。测试环境:chrome@131.0.6778.70nodejs@20.18.0

抛出一个错误

throw new Error("这是个带stack的error");

可以看到,在没有try{}catch(){}的情况下,会显示具体的调试信息。例如:

Error: 这是个带stack的error
    at D:\test\express.js:4:9
    at Layer.handle [as handle_request] (D:\test\node_modules\express\lib\router\layer.js:95:5)
    at next (D:\test\node_modules\express\lib\router\route.js:149:13)
    at Route.dispatch (D:\test\node_modules\express\lib\router\route.js:119:3)
    at Layer.handle [as handle_request] (D:\test\node_modules\express\lib\router\layer.js:95:5)
    at D:\test\node_modules\express\lib\router\index.js:284:15
    at Function.process_params (D:\test\node_modules\express\lib\router\index.js:346:12)
    at next (D:\test\node_modules\express\lib\router\index.js:280:10)
    at expressInit (D:\test\node_modules\express\lib\middleware\init.js:40:5)
    at Layer.handle [as handle_request] (D:\test\node_modules\express\lib\router\layer.js:95:5)

方案一,清空stack

错误定义好之后,清空stack属性即可,这个是最简单的方案。

let e = new Error("这是个带stack的error");
e.stack = "";
throw e;

苏南大叔:JavaScript,如何抛出一个不带堆栈调试信息的error? - 清空error的堆栈信息
JavaScript,如何抛出一个不带堆栈调试信息的error?(图4-2)

方案二,CustomError

继承Error,使用CustomError做类定义进行初始化,这样的操作很常规化。如果一个项目里面,有很多本文的需求的话,就可以选择这个方案。

class CustomError extends Error {
  constructor(message) {
    super(message);
    this.name = "CustomError";
    // Error.captureStackstack(this, this.constructor); // 为了兼容性,确保stack包含message
    this.stack = "";
  }
}
throw new CustomError("这是个不带stack的CustomError");

方案三,改写Error

这个方案就略显极端了,使用Proxy改写Error这个类定义。很极端...。悄咪咪的,以后所有的Error都不带调试信息了。

Error = new Proxy(Error, {
  construct: function (target, args) {
    var obj_tmp = new target(...args);
    obj_tmp.stack = "";
    return obj_tmp;
  },
});
// console.log(e instanceof Error); // true
throw new Error("这是个不带stack的修改版Error");

苏南大叔:JavaScript,如何抛出一个不带堆栈调试信息的error? - 改写error类
JavaScript,如何抛出一个不带堆栈调试信息的error?(图4-3)

参考文章:

题外话,express的代码机制

本文以express提供的网络接口作为载体,演示本文的内容。当然,普通的node代码或者浏览器运行环境里面,也是可以运行生效的。

测试基础代码(仅龙套,没实际意义):

const express = require("express");
const app = express();
app.get("/", function (req, res) {
  // ##################################
  // 测试代码放这里
  // ##################################
  res.send("苏南大叔的博客:newsn.net");
});
const server = app.listen(process.env.PORT || 3222, () => {
  const port = server.address().port;
  console.log("http://localhost:%d", port);
});

虽然这个被改写的Error类被定义在某个路由下面,但是一旦访问了这个路由,其它的本来会被输出调试信息的路由,也会被一并改写生效,变成不输出stack信息。

苏南大叔:JavaScript,如何抛出一个不带堆栈调试信息的error? - 深入思考
JavaScript,如何抛出一个不带堆栈调试信息的error?(图4-4)

这就深深的引发思考了,php下正常情况下来说,是肯定不会发生这样的事情的。两个不同的请求绝对不会相互干扰。而这个express的代码,两个请求中居然会相互干涉... 这说明了什么?就本文的代码来说,先访问/4,再访问/,就会发现这个问题。Error的改写被应用到全局了......................................

参考文章:

结语

本文清空Error的堆栈信息,其核心点就一句话.stack=""。更多苏南大叔的js调试经验文章,请参考:

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   js