diff --git a/app/middleware/notfound.js b/app/middleware/notfound.js
index f97562cd4e..daaf28705b 100644
--- a/app/middleware/notfound.js
+++ b/app/middleware/notfound.js
@@ -18,16 +18,19 @@ module.exports = options => {
return;
}
- if (options.enableRedirect && options.pageUrl) {
+ const notFoundHtml = '
404 Not Found
';
+
+ // notfound handler is unimplemented
+ if (options.pageUrl && this.path === options.pageUrl) {
+ this.body = `${notFoundHtml}config.notfound.pageUrl(${options.pageUrl})
is unimplemented`;
+ return;
+ }
+
+ if (options.pageUrl) {
this.realStatus = 404;
this.redirect(options.pageUrl);
return;
}
- const title = '404 Not Found
';
- if (!options.enableRedirect && options.pageUrl) {
- this.body = `${title}Because you are in a non-prod environment, you will be looking at this page, otherwise it will jump to ${options.pageUrl}`;
- } else {
- this.body = title;
- }
+ this.body = notFoundHtml;
};
};
diff --git a/config/config.default.js b/config/config.default.js
index dc22505bed..254d766cd1 100644
--- a/config/config.default.js
+++ b/config/config.default.js
@@ -106,7 +106,6 @@ module.exports = appInfo => {
*/
exports.notfound = {
pageUrl: '',
- enableRedirect: appInfo.env === 'prod',
};
/**
diff --git a/docs/source/zh-cn/core/error-handling.md b/docs/source/zh-cn/core/error-handling.md
index 96161646ee..0e096456b7 100644
--- a/docs/source/zh-cn/core/error-handling.md
+++ b/docs/source/zh-cn/core/error-handling.md
@@ -52,15 +52,15 @@ this.runInBackground(function* () {
| 请求需求的格式 | 环境 | errorPageUrl 是否配置 | 返回内容 |
|-------------|------|----------------------|--------|
-| html & text | local & unittest | - | onerror 自带的错误页面,展示详细的错误信息 |
-| html & text | 其他 | 是 | 重定向到 errorPageUrl |
-| html & text | 其他 | 否 | onerror 自带的没有错误信息的简单错误页(不推荐) |
-| json | local & unittest | - | json 对象,带详细的错误信息 |
-| json | 其他 | - | json 对象,不带详细的错误信息 |
+| HTML & TEXT | local & unittest | - | onerror 自带的错误页面,展示详细的错误信息 |
+| HTML & TEXT | 其他 | 是 | 重定向到 errorPageUrl |
+| HTML & TEXT | 其他 | 否 | onerror 自带的没有错误信息的简单错误页(不推荐) |
+| JSON | local & unittest | - | JSON 对象,带详细的错误信息 |
+| JSON | 其他 | - | json 对象,不带详细的错误信息 |
### errorPageUrl
-onerror 插件的配置中支持 errorPageUrl 属性,当配置了 errorPageUrl 时,一旦用户请求线上应用的 html 页面异常,就会重定向到这个地址。
+onerror 插件的配置中支持 errorPageUrl 属性,当配置了 errorPageUrl 时,一旦用户请求线上应用的 HTML 页面异常,就会重定向到这个地址。
在 `config/config.default.js` 中
@@ -111,3 +111,56 @@ module.exports = {
},
};
```
+
+## 404
+
+框架并不会将服务端返回的 404 状态当做异常来处理,但是框架提供了当响应为 404 且没有返回 body 时的默认响应。
+
+- 当请求被框架判定为需要 JSON 格式的响应时,会返回一段 JSON:
+
+ ```json
+ { "message": "Not Found" }
+ ```
+
+- 当请求被框架判定为需要 HTML 格式的响应时,会返回一段 HTML:
+
+ ```html
+ 404 Not Found
+ ```
+
+框架支持通过配置,将默认的 HTML 请求的 404 响应重定向到指定的页面。
+
+```js
+// config/config.default.js
+module.exports = {
+ notfound: {
+ pageUrl: '/404.html',
+ },
+};
+```
+
+### 自定义 404 响应
+
+在一些场景下,我们需要自定义服务器 404 时的响应,和自定义异常处理一样,我们也只需要加入一个中间件即可对 404 做统一处理:
+
+```js
+// app/middleware/notfound_handler.js
+module.exports = () => {
+ return function* (next) {
+ yield next;
+ if (this.status === 404 && !this.body) {
+ if (this.acceptJSON) this.body = { error: 'Not Found' };
+ else this.body = 'Page Not Found
';
+ }
+ };
+};
+```
+
+在配置中引入中间件:
+
+```js
+// config/config.default.js
+module.exports = {
+ middleware: [ 'notfoundHander' ],
+};
+```
diff --git a/test/app/middleware/notfound.test.js b/test/app/middleware/notfound.test.js
index 5d5f4c8ae7..e5182d29e8 100644
--- a/test/app/middleware/notfound.test.js
+++ b/test/app/middleware/notfound.test.js
@@ -1,6 +1,5 @@
'use strict';
-const pedding = require('pedding');
const request = require('supertest');
const mm = require('egg-mock');
const utils = require('../../utils');
@@ -15,8 +14,7 @@ describe('test/app/middleware/notfound.test.js', () => {
afterEach(mm.restore);
- it('should 302 redirect to 404.html on production env', () => {
- mm(app.config.notfound, 'enableRedirect', true);
+ it('should 302 redirect to 404.html', () => {
return request(app.callback())
.get('/test/404')
.set('Accept', 'test/html')
@@ -24,13 +22,6 @@ describe('test/app/middleware/notfound.test.js', () => {
.expect(302);
});
- it('should show 404 on dev env', () => {
- return request(app.callback())
- .get('/test/404')
- .expect('404 Not Found
Because you are in a non-prod environment, you will be looking at this page, otherwise it will jump to https://eggjs.org/404')
- .expect(404);
- });
-
it('should 404 json response', () => {
return request(app.callback())
.get('/test/404.json?ctoken=404')
@@ -59,7 +50,7 @@ describe('test/app/middleware/notfound.test.js', () => {
.expect(404);
});
- describe('app.404.url=/404', () => {
+ describe('config.notfound.pageUrl = "/404"', () => {
let app;
before(() => {
app = utils.app('apps/notfound-custom-404');
@@ -69,20 +60,32 @@ describe('test/app/middleware/notfound.test.js', () => {
afterEach(mm.restore);
- it('should 302 redirect to custom /404 on production env', done => {
- done = pedding(2, done);
- mm(app.config.notfound, 'enableRedirect', true);
-
- request(app.callback())
+ it('should 302 redirect to custom /404 when required html', function* () {
+ yield request(app.callback())
.get('/test/404')
.set('Accept', 'test/html')
.expect('Location', '/404')
- .expect(302, done);
+ .expect(302);
- request(app.callback())
+ yield request(app.callback())
.get('/404')
.expect('Hi, this is 404')
- .expect(200, done);
+ .expect(200);
+ });
+
+ it('should not avoid circular redirects', function* () {
+ mm(app.config.notfound, 'pageUrl', '/notfound');
+
+ yield request(app.callback())
+ .get('/test/404')
+ .set('Accept', 'test/html')
+ .expect('Location', '/notfound')
+ .expect(302);
+
+ yield request(app.callback())
+ .get('/notfound')
+ .expect('404 Not Found
config.notfound.pageUrl(/notfound)
is unimplemented')
+ .expect(404);
});
});
});