惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

有赞技术团队
有赞技术团队
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
P
Palo Alto Networks Blog
C
Cisco Blogs
The Hacker News
The Hacker News
T
Threatpost
S
Schneier on Security
K
Kaspersky official blog
Spread Privacy
Spread Privacy
博客园_首页
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
NISL@THU
NISL@THU
量子位
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Google DeepMind News
Google DeepMind News
Security Latest
Security Latest
博客园 - 司徒正美
云风的 BLOG
云风的 BLOG
博客园 - 叶小钗
H
Hackread – Cybersecurity News, Data Breaches, AI and More
N
News and Events Feed by Topic
爱范儿
爱范儿
P
Proofpoint News Feed
C
CERT Recently Published Vulnerability Notes
Project Zero
Project Zero
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Cisco Talos Blog
Cisco Talos Blog
GbyAI
GbyAI
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Apple Machine Learning Research
Apple Machine Learning Research
T
Tenable Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
V
Vulnerabilities – Threatpost
Forbes - Security
Forbes - Security
博客园 - 三生石上(FineUI控件)
C
Cyber Attacks, Cyber Crime and Cyber Security
N
News and Events Feed by Topic
V
V2EX
Webroot Blog
Webroot Blog
The Register - Security
The Register - Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
阮一峰的网络日志
阮一峰的网络日志
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Blog — PlanetScale
Blog — PlanetScale
M
MIT News - Artificial intelligence
Scott Helme
Scott Helme
Simon Willison's Weblog
Simon Willison's Weblog
L
LangChain Blog
W
WeLiveSecurity
Cloudbric
Cloudbric

博客园 - MK2

cnpmcore 超大 JSON parse 性能优化 基于 Postgres 实现一个 Job Queue Graceful exit with cluster and pm Use Blanket.js instead of jscover Defense hash algorithm collision 防御hash算法冲突导致拒绝服务器 fibonacci(40) benchmark [nodejs]保证你的程序死了还能复活:forever and forever webui [nodejs]Buffer vs String Nodejs "Hello world" benchmark npm 资源库镜像 NodeBlog v0.2.0 更新说明 关于__proto__的链式记忆 NAE支持自定义域名了 Nodejs 离线文档下载 nodejs读写大文件 Nodejs HTTP请求的超时处理(Nodejs HTTP Client Request Timeout Handle) 在jQuery 1.5+ 的jqXHR上监听文件上传进度(xhr.upload) 关于Nodejs中Buffer释放的二三事 nodejs web开发入门: Simple-TODO Nodejs 实现版
使用 connect-domain 捕获异步调用中出现的异常
MK2 · 2012-12-27 · via 博客园 - MK2

之前经常有同学会问到怎么有些异常无法捕获到呢?

虽然 connect 已经在 handler 外层加了 try catch ,还是无法捕获异步调用中产生的异常。

现状

例如最简单的 helloworld.js 代码

var connect = require('connect');

var app = connect()
.use(function (req, res, next) {
  if (req.url === '/sync_error') {
    throw new Error('sync error');
  }
  if (req.url === '/async_error') {
    return process.nextTick(function () {
      mk2.haha();
    });
  }
  res.end('hello, ' + req.method + ' ' + req.url);
});

process.on('uncaughtException', function (err) {
  console.error(err);
});

app.listen(1985);

使用 curl 来简单测试一下

$ curl localhost:1985/foo
hello, GET /foo

$ curl localhost:1985/sync_error
Error: sync error
    at Object.handle ( .../app.js:33:11)
    ....

好像还挺正常的,异常也被捕获了。 继续测试

$ curl localhost:1985/async_error

没任何输出了吧?从服务器端控制台看到这样的输出: 证明触发了 uncaughtException 事件。

[ReferenceError: mk2 is not defined]

虽然我们能通过 uncaughtException 事件捕获到异步调用中产生的异常,但是我们没办法返回 HTTP 500 异常响应给调用者。 调用者也只能一直hold住,直到请求超时。

这是非常不好的做法,因为请求量很大,服务进程内存会暴涨,会导致进程超出内存限制,非正常退出。

改进

任何时候,如果服务器端出现异常,我们就应该返回HTTP 500 告诉调用者服务器异常了。

异步调用产生的异常也应该如此处理。

nodejs@0.8 开始,增加了 domain 模块来帮助我们更好地处理异常。

让我们使用 connect-domain 来改进一下之前的 helloworld.js:

var connect = require('connect');
var connectDomain = require('connect-domain');

var app = connect()
.use(connectDomain()) // just using connect-domian middleware
.use(function (req, res, next) {
  if (req.url === '/sync_error') {
    throw new Error('sync error');
  }
  if (req.url === '/async_error') {
    return process.nextTick(function () {
      mk2.haha();
    });
  }
  res.end('hello, ' + req.method + ' ' + req.url);
});

process.on('uncaughtException', function (err) {
  console.error(err);
});

app.listen(1984);

再看看 connect-domain 的实现,非常简单:

var domain = require('domain');

module.exports = function (handler) {
  return function domainMiddleware(req, res, next) {
    var reqDomain = domain.create();

    res.on('close', function () {
      reqDomain.dispose();
    });

    reqDomain.on('error', function (err) {
      if (typeof handler === 'function') {
        handler(err, req, res, next);
      } else {
        next(err);
      }
    });

    reqDomain.run(next);
  };
};

重复刚才的 curl 测试:

$ curl localhost:1984/foo
hello, GET /foo

$ curl localhost:1984/sync_error
Error: sync error
    at Object.handle ( .../app.js:33:11)
    ....

$ curl localhost:1984/async_error
ReferenceError: mk2 is not defined
    at .../app.js:24:7
    at process.startup.processNextTick.process._tickCallback (node.js:244:9)

所有请求都有响应了。

服务器进程的输出:

{ [ReferenceError: mk2 is not defined]
  domain_thrown: true,
  domain: 
   { domain: null,
     _events: { error: [Function] },
     _maxListeners: 10,
     members: [] } }

奇怪的连 uncaughtException 事件也触发了。这按我的思维来说,不应该触发才对的。

@isaacs 最新的提交已经修复此问题: https://github.com/joyent/node/issues/4375#issuecomment-11691069

总结

应该没人再说 nodejs 无法捕获异步调用中出现的异常了吧?