Skip to content

Commit a440425

Browse files
committedMar 13, 2016
Add support for headers in errors
1 parent 3d15c24 commit a440425

File tree

3 files changed

+80
-1
lines changed

3 files changed

+80
-1
lines changed
 

‎docs/error-handling.md

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Error Handling
2+
3+
## Try-Catch
4+
5+
Using generators means that you can try-catch `next`. For example,
6+
this example prepends all error messages with "Error: "
7+
8+
```js
9+
app.use(function*(next){
10+
try {
11+
yield next;
12+
} catch (error) {
13+
error.message = 'Error: ' + error.message;
14+
throw error;
15+
}
16+
});
17+
```
18+
19+
### Default Error Handler
20+
21+
The default error handler is essentially a try-catch at
22+
the very beginning of the middleware chain. To use a
23+
different error handler, simply put another try-catch at
24+
the beginning of the middleware chain, and handle the error
25+
there. However, the default error handler is good enough for
26+
most use cases. It will use a status code of `err.status`,
27+
or by default 500. If `err.expose` is true, then `err.message`
28+
will be the reply. Otherwise, a message generated from the
29+
error code will be used (e.g. for the code 500 the message
30+
"Internal Server Error" will be used). All headers will be
31+
cleared from the request, but any headers in `err.headers`
32+
will then be set. You can use a try-catch, as specified
33+
above, to add a header to this list.
34+
35+
## The Error Event
36+
37+
Error handlers can be specified with `app.on('error')`.
38+
If no error handler is specified, a default error handler
39+
is used. Error handlers recieve all errors that make their
40+
way back through the middleware chain, if an error is caught
41+
and not thrown again, it will not be handled by the error
42+
handler. If not error event handler is specified, then
43+
`app.onerror` will be used, which simply log the error if
44+
`error.expose` is true and `app.silent` is false.

‎lib/context.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,9 @@ const proto = module.exports = {
117117
return;
118118
}
119119

120-
// unset all headers
120+
// unset all headers, and set those specified
121121
this.res._headers = {};
122+
this.set(err.headers);
122123

123124
// force text/plain
124125
this.type = 'text';

‎test/context/onerror.js

+34
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,40 @@ describe('ctx.onerror(err)', () => {
5252
});
5353
});
5454

55+
it('should set headers specified in the error', done => {
56+
const app = new Koa();
57+
58+
app.use((ctx, next) => {
59+
ctx.set('Vary', 'Accept-Encoding');
60+
ctx.set('X-CSRF-Token', 'asdf');
61+
ctx.body = 'response';
62+
63+
throw Object.assign(new Error('boom'), {
64+
status: 418,
65+
expose: true,
66+
headers: {
67+
'X-New-Header': 'Value'
68+
}
69+
});
70+
});
71+
72+
const server = app.listen();
73+
74+
request(server)
75+
.get('/')
76+
.expect(418)
77+
.expect('Content-Type', 'text/plain; charset=utf-8')
78+
.expect('X-New-Header', 'Value')
79+
.end((err, res) => {
80+
if (err) return done(err);
81+
82+
res.headers.should.not.have.property('vary');
83+
res.headers.should.not.have.property('x-csrf-token');
84+
85+
done();
86+
});
87+
});
88+
5589
describe('when invalid err.status', () => {
5690
describe('not number', () => {
5791
it('should respond 500', done => {

0 commit comments

Comments
 (0)
Please sign in to comment.