added expressjs error handler/native npm package

This commit is contained in:
Andi Dittrich 2017-05-15 07:45:35 +00:00
parent 8665d862e3
commit 019dcc81af
24 changed files with 490 additions and 24 deletions

1
.gitignore vendored
View file

@ -4,4 +4,5 @@
.buildpath
.git
gfx/*
node_modules*
PublicHtml/*

View file

@ -60,6 +60,40 @@ location /ErrorPages/ {
}
```
## expressjs Integration ##
HttpErrorPages are available as NPM-Package - just install `http-error-pages` via **npm/yarn**
```terminal
npm install http-error-pages --save
```
Example
```js
var _express = require('express');
var _webapp = _express();
var _httpErrorPages = require('http-error-pages');
// demo handler
_webapp.get('/', function(req, res){
res.type('.txt').send('HttpErrorPages Demo');
});
// throw an 403 error
_webapp.get('/my403error', function(req, res, next){
var myError = new Error();
myError.status = 403;
next(myError);
});
// use http error pages handler (final statement!)
_httpErrorPages(_webapp);
// start service
_webapp.listen(8888);
```
## Apache Httpd Integration ##
[Apache Httpd 2.x](http://httpd.apache.org/) supports custom error-pages using multiple [ErrorDocument](http://httpd.apache.org/docs/2.4/mod/core.html#errordocument) directives.

22
dist/HTTP0.html vendored Normal file
View file

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Simple HttpErrorPages | MIT X11 License | https://github.com/AndiDittrich/HttpErrorPages -->
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>We've got some trouble | {{code}} - {{title}}</title>
<style type="text/css">/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}template{display:none}[hidden]{display:none}/*! Simple HttpErrorPages | MIT X11 License | https://github.com/AndiDittrich/HttpErrorPages */body,html{width:100%;height:100%;background-color:#21232a}body{color:#fff;text-align:center;text-shadow:0 2px 4px rgba(0,0,0,.5);padding:0;min-height:100%;-webkit-box-shadow:inset 0 0 75pt rgba(0,0,0,.8);box-shadow:inset 0 0 75pt rgba(0,0,0,.8);display:table;font-family:"Open Sans",Arial,sans-serif}h1{font-family:inherit;font-weight:500;line-height:1.1;color:inherit;font-size:36px}h1 small{font-size:68%;font-weight:400;line-height:1;color:#777}a{text-decoration:none;color:#fff;font-size:inherit;border-bottom:dotted 1px #707070}.lead{color:silver;font-size:21px;line-height:1.4}.cover{display:table-cell;vertical-align:middle;padding:0 20px}footer{position:fixed;width:100%;height:40px;left:0;bottom:0;color:#a0a0a0;font-size:14px}</style>
</head>
<body>
<div class="cover">
<h1>{{title}} <small>Error {{code}}</small></h1>
<p class="lead">{{message}}</p>
</div>
</body>
</html>

3
dist/HTTP400.html vendored
View file

@ -18,6 +18,5 @@
<p class="lead">The server cannot process the request due to something that is perceived to be a client error.</p>
</div>
</body>
</body>
</html>

3
dist/HTTP401.html vendored
View file

@ -18,6 +18,5 @@
<p class="lead">The requested resource requires an authentication.</p>
</div>
</body>
</body>
</html>

3
dist/HTTP403.html vendored
View file

@ -18,6 +18,5 @@
<p class="lead">The requested resource requires an authentication.</p>
</div>
</body>
</body>
</html>

3
dist/HTTP404.html vendored
View file

@ -18,6 +18,5 @@
<p class="lead">The requested resource could not be found but may be available again in the future.</p>
</div>
</body>
</body>
</html>

3
dist/HTTP500.html vendored
View file

@ -19,6 +19,5 @@
Our service team has been dispatched to bring it back online.</p>
</div>
</body>
</body>
</html>

3
dist/HTTP501.html vendored
View file

@ -18,6 +18,5 @@
<p class="lead">The Webserver cannot recognize the request method.</p>
</div>
</body>
</body>
</html>

3
dist/HTTP502.html vendored
View file

@ -19,6 +19,5 @@
Our service team has been dispatched to bring it back online.</p>
</div>
</body>
</body>
</html>

3
dist/HTTP503.html vendored
View file

@ -19,6 +19,5 @@
Our service team has been dispatched to bring it back online.</p>
</div>
</body>
</body>
</html>

3
dist/HTTP520.html vendored
View file

@ -18,6 +18,5 @@
<p class="lead">The requested hostname is not routed. Use only hostnames to access resources.</p>
</div>
</body>
</body>
</html>

3
dist/HTTP521.html vendored
View file

@ -19,6 +19,5 @@
Our service team has been dispatched to bring it back online.</p>
</div>
</body>
</body>
</html>

3
dist/HTTP533.html vendored
View file

@ -19,6 +19,5 @@
Our service team is working hard to bring it back online soon.</p>
</div>
</body>
</body>
</html>

BIN
dist/pages.tar vendored

Binary file not shown.

BIN
dist/pages.zip vendored

Binary file not shown.

22
express-demo.js Normal file
View file

@ -0,0 +1,22 @@
var _express = require('express');
var _webapp = _express();
var _httpErrorPages = require('./lib/error-handler');
// demo handler
_webapp.get('/', function(req, res){
res.type('.txt').send('HttpErrorPages Demo');
});
// throw an 403 error
_webapp.get('/my403error', function(req, res, next){
var myError = new Error();
myError.status = 403;
next(myError);
});
// use http error pages handler (final statement!)
_httpErrorPages(_webapp);
// start service
_webapp.listen(8888);
console.log('Running Demo on Port 8888');

View file

@ -30,12 +30,19 @@ file_put_contents('dist/pages.json', json_encode($pages));
// load inline css
$css = trim(file_get_contents('assets/Layout.css'));
// js template page
$pages['{{code}}'] = array(
'title' => '{{title}}',
'message' => '{{message}}',
'footer' => '{{footer}}'
);
// generate each error page
foreach ($pages as $code => $page){
echo 'Generating Page ', $page['title'], ' (', $code, ')..', PHP_EOL;
// assign variables
$v_code = intval($code);
$v_code = $code;
$v_title = nl2br(htmlspecialchars($page['title']));
$v_message = nl2br(htmlspecialchars($page['message']));
$v_footer = (isset($config['footer']) ? $config['footer'] : '');

47
lib/dispatcher.js Normal file
View file

@ -0,0 +1,47 @@
var _pages = require('../dist/pages.json');
var _renderer = require('./page-renderer');
// multi-type support
// @see https://github.com/expressjs/express/blob/master/examples/error-pages/index.js
function dispatchRequest(page, httpStatusCode, req, res){
// page available ?
if (!_pages[page]){
// use "internal server error" as default
page = '500';
httpStatusCode = null;
}
// set http status code
res.status(httpStatusCode || 500);
// extract page date
var pageData = _pages[page];
// multiple response formats
res.format({
// standard http-error-pages
html: function(){
res.type('.html');
res.send(_renderer({
code: httpStatusCode,
title: pageData.title,
message: pageData.message
}))
},
// json
json: function(){
res.json({
error: pageData.title + ' - ' + pageData.message
})
},
// text response
default: function(){
// plain text
res.type('.txt').send(pageData.title + ' - ' + pageData.message);
}
})
}
module.exports = dispatchRequest;

27
lib/error-handler.js Normal file
View file

@ -0,0 +1,27 @@
var _dispatcher = require('./dispatcher');
// http404 handler
function notfoundHandler(req, res){
_dispatcher('404', 404, req, res);
}
// default error handler
function errorHandler(err, req, res, next){
// status code given ?
if (err.status){
// custom errorpage set ?
_dispatcher(err.errorpage || err.status, err.status, req, res);
// use default http500 page
}else{
_dispatcher('500', 500, req, res);
}
};
module.exports = function(router){
// 404
router.use(notfoundHandler);
// internal errors (all)
router.use(errorHandler);
};

27
lib/page-renderer.js Normal file
View file

@ -0,0 +1,27 @@
var _path = require('path');
var _fs = require('fs');
var _basedir = _path.dirname(__dirname);
// load template file (1 time)
var _template = _fs.readFileSync(_path.join(_basedir, 'dist/HTTP0.html'), 'utf8');
// simple template renderer
function renderPage(vars){
var tpl = _template;
// add vars
tpl = tpl.replace(/{{([a-z]+)}}/gm, function(match, name){
// var available ?
if (vars[name]){
return vars[name];
// remove unused vars
}else{
return '';
}
});
return tpl;
}
module.exports = renderPage;

33
package.json Normal file
View file

@ -0,0 +1,33 @@
{
"name": "http-error-pages",
"version": "0.1.0",
"description": "Simple HTTP Error Pages for expressjs",
"keywords": [
"http",
"https",
"error",
"errorpage",
"express",
"expressjs",
"router",
"handler"
],
"files": [
"bin",
"dist",
"express-demo.js",
"CHANGED.md",
"LICENSE.md",
"README.md"
],
"bin": {},
"main": "./lib/router.js",
"author": "Andi Dittrich (https://andidittrich.de)",
"homepage": "https://github.com/AndiDittrich/HttpErrorPages",
"bugs": "https://github.com/AndiDittrich/HttpErrorPages/issues",
"repository": "AndiDittrich/HttpErrorPages",
"license": "MIT",
"devDependencies": {
"express": "^4.15.2"
}
}

View file

@ -22,6 +22,6 @@
<footer>
<p><?php echo $v_footer; ?></p>
</footer>
<?php } ?>
<?php } ?>
</body>
</html>

257
yarn.lock Normal file
View file

@ -0,0 +1,257 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
accepts@~1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca"
dependencies:
mime-types "~2.1.11"
negotiator "0.6.1"
array-flatten@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
content-disposition@0.5.2:
version "0.5.2"
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4"
content-type@~1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed"
cookie-signature@1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
cookie@0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
debug@2.6.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.1.tgz#79855090ba2c4e3115cc7d8769491d58f0491351"
dependencies:
ms "0.7.2"
debug@2.6.4:
version "2.6.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.4.tgz#7586a9b3c39741c0282ae33445c4e8ac74734fe0"
dependencies:
ms "0.7.3"
depd@1.1.0, depd@~1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3"
destroy@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
ee-first@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
encodeurl@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20"
escape-html@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
etag@~1.8.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.0.tgz#6f631aef336d6c46362b51764044ce216be3c051"
express@^4.15.2:
version "4.15.2"
resolved "https://registry.yarnpkg.com/express/-/express-4.15.2.tgz#af107fc148504457f2dca9a6f2571d7129b97b35"
dependencies:
accepts "~1.3.3"
array-flatten "1.1.1"
content-disposition "0.5.2"
content-type "~1.0.2"
cookie "0.3.1"
cookie-signature "1.0.6"
debug "2.6.1"
depd "~1.1.0"
encodeurl "~1.0.1"
escape-html "~1.0.3"
etag "~1.8.0"
finalhandler "~1.0.0"
fresh "0.5.0"
merge-descriptors "1.0.1"
methods "~1.1.2"
on-finished "~2.3.0"
parseurl "~1.3.1"
path-to-regexp "0.1.7"
proxy-addr "~1.1.3"
qs "6.4.0"
range-parser "~1.2.0"
send "0.15.1"
serve-static "1.12.1"
setprototypeof "1.0.3"
statuses "~1.3.1"
type-is "~1.6.14"
utils-merge "1.0.0"
vary "~1.1.0"
finalhandler@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.2.tgz#d0e36f9dbc557f2de14423df6261889e9d60c93a"
dependencies:
debug "2.6.4"
encodeurl "~1.0.1"
escape-html "~1.0.3"
on-finished "~2.3.0"
parseurl "~1.3.1"
statuses "~1.3.1"
unpipe "~1.0.0"
forwarded@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363"
fresh@0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.0.tgz#f474ca5e6a9246d6fd8e0953cfa9b9c805afa78e"
http-errors@~1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.1.tgz#5f8b8ed98aca545656bf572997387f904a722257"
dependencies:
depd "1.1.0"
inherits "2.0.3"
setprototypeof "1.0.3"
statuses ">= 1.3.1 < 2"
inherits@2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
ipaddr.js@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.3.0.tgz#1e03a52fdad83a8bbb2b25cbf4998b4cffcd3dec"
media-typer@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
merge-descriptors@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
methods@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
mime-db@~1.27.0:
version "1.27.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1"
mime-types@~2.1.11, mime-types@~2.1.15:
version "2.1.15"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed"
dependencies:
mime-db "~1.27.0"
mime@1.3.4:
version "1.3.4"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53"
ms@0.7.2:
version "0.7.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765"
ms@0.7.3:
version "0.7.3"
resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.3.tgz#708155a5e44e33f5fd0fc53e81d0d40a91be1fff"
negotiator@0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
on-finished@~2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
dependencies:
ee-first "1.1.1"
parseurl@~1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56"
path-to-regexp@0.1.7:
version "0.1.7"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
proxy-addr@~1.1.3:
version "1.1.4"
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.4.tgz#27e545f6960a44a627d9b44467e35c1b6b4ce2f3"
dependencies:
forwarded "~0.1.0"
ipaddr.js "1.3.0"
qs@6.4.0:
version "6.4.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
range-parser@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
send@0.15.1:
version "0.15.1"
resolved "https://registry.yarnpkg.com/send/-/send-0.15.1.tgz#8a02354c26e6f5cca700065f5f0cdeba90ec7b5f"
dependencies:
debug "2.6.1"
depd "~1.1.0"
destroy "~1.0.4"
encodeurl "~1.0.1"
escape-html "~1.0.3"
etag "~1.8.0"
fresh "0.5.0"
http-errors "~1.6.1"
mime "1.3.4"
ms "0.7.2"
on-finished "~2.3.0"
range-parser "~1.2.0"
statuses "~1.3.1"
serve-static@1.12.1:
version "1.12.1"
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.12.1.tgz#7443a965e3ced647aceb5639fa06bf4d1bbe0039"
dependencies:
encodeurl "~1.0.1"
escape-html "~1.0.3"
parseurl "~1.3.1"
send "0.15.1"
setprototypeof@1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04"
"statuses@>= 1.3.1 < 2", statuses@~1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e"
type-is@~1.6.14:
version "1.6.15"
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410"
dependencies:
media-typer "0.3.0"
mime-types "~2.1.15"
unpipe@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
utils-merge@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8"
vary@~1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37"