errorHandler.js 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. /*!
  2. * Connect - errorHandler
  3. * Copyright(c) 2010 Sencha Inc.
  4. * Copyright(c) 2011 TJ Holowaychuk
  5. * MIT Licensed
  6. */
  7. /**
  8. * Module dependencies.
  9. */
  10. var utils = require('../utils')
  11. , fs = require('fs');
  12. // environment
  13. var env = process.env.NODE_ENV || 'development';
  14. /**
  15. * Error handler:
  16. *
  17. * Development error handler, providing stack traces
  18. * and error message responses for requests accepting text, html,
  19. * or json.
  20. *
  21. * Text:
  22. *
  23. * By default, and when _text/plain_ is accepted a simple stack trace
  24. * or error message will be returned.
  25. *
  26. * JSON:
  27. *
  28. * When _application/json_ is accepted, connect will respond with
  29. * an object in the form of `{ "error": error }`.
  30. *
  31. * HTML:
  32. *
  33. * When accepted connect will output a nice html stack trace.
  34. *
  35. * @return {Function}
  36. * @api public
  37. */
  38. exports = module.exports = function errorHandler(){
  39. return function errorHandler(err, req, res, next){
  40. if (err.status) res.statusCode = err.status;
  41. if (res.statusCode < 400) res.statusCode = 500;
  42. if ('test' != env) console.error(err.stack);
  43. var accept = req.headers.accept || '';
  44. // html
  45. if (~accept.indexOf('html')) {
  46. fs.readFile(__dirname + '/../public/style.css', 'utf8', function(e, style){
  47. fs.readFile(__dirname + '/../public/error.html', 'utf8', function(e, html){
  48. var stack = (err.stack || '')
  49. .split('\n').slice(1)
  50. .map(function(v){ return '<li>' + v + '</li>'; }).join('');
  51. html = html
  52. .replace('{style}', style)
  53. .replace('{stack}', stack)
  54. .replace('{title}', exports.title)
  55. .replace('{statusCode}', res.statusCode)
  56. .replace(/\{error\}/g, utils.escape(err.toString()));
  57. res.setHeader('Content-Type', 'text/html; charset=utf-8');
  58. res.end(html);
  59. });
  60. });
  61. // json
  62. } else if (~accept.indexOf('json')) {
  63. var error = { message: err.message, stack: err.stack };
  64. for (var prop in err) error[prop] = err[prop];
  65. var json = JSON.stringify({ error: error });
  66. res.setHeader('Content-Type', 'application/json');
  67. res.end(json);
  68. // plain text
  69. } else {
  70. res.writeHead(res.statusCode, { 'Content-Type': 'text/plain' });
  71. res.end(err.stack);
  72. }
  73. };
  74. };
  75. /**
  76. * Template title, framework authors may override this value.
  77. */
  78. exports.title = 'Connect';