egg-project
├── package.json
├── app.js (可选)
├── agent.js (可选)
├── app
| ├── router.js
│ ├── controller
│ | └── home.js
│ ├── service (可选)
│ | └── user.js
│ ├── middleware (可选)
│ | └── response_time.js
│ ├── schedule (可选)
│ | └── my_task.js
│ ├── public (可选)
│ | └── reset.css
│ ├── view (可选)
│ | └── home.tpl
│ └── extend (可选)
│ ├── helper.js (可选)
│ ├── request.js (可选)
│ ├── response.js (可选)
│ ├── context.js (可选)
│ ├── application.js (可选)
│ └── agent.js (可选)
├── config
| ├── plugin.js
| ├── config.default.js
│ ├── config.prod.js
| ├── config.test.js (可选)
| ├── config.local.js (可选)
| └── config.unittest.js (可选)
└── test
├── middleware
| └── response_time.test.js
└── controller
└── home.test.js
mkdir egg-news
cd egg-news
npm init -y
cnpm i egg --save
cnpm i egg-bin --save-dev
"scripts": {
"dev": "egg-bin dev"
}
├─app
│ │─router.js
│ ├─controller
│ │ news.js
├─config
│ config.default.js
|─package.json
app/router.js
module.exports = app => {
const { router, controller } = app;
router.get('/news', controller.news.index);
}
app\controller\news.js
const { Controller } = require('egg');
class NewsController extends Controller {
async index() {
this.ctx.body = 'hello world';
}
}
module.exports = NewsController;
exports.keys = 'zfpx';
├─app
│ │─router.js
│ ├─controller
│ │ news.js
│ ├─public
│ │ ├─css
│ │ │ bootstrap.css
│ │ └─js
│ │ bootstrap.js
│ └─view
│ news.ejs
├─config
│ config.default.js
│ plugin.js
cnpm install egg-view-ejs --save
{ROOT}\config\plugin.js
exports.ejs = {
enable: true,
package: 'egg-view-ejs'
}
{ROOT}\config\config.default.js
exports.view = {
defaultViewEngine: 'ejs',
mapping: {
'.ejs': 'ejs'
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="/public/css/bootstrap.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>百度新闻列表</title>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-sm">
<div class="card">
<div class="card-header">
百度新闻列表
</div>
<div class="card-block">
<ul class="list-group">
<%news.forEach(item=>{ %>
<li class="list-group-item">
<a href="<%=item.url%>">
<%=item.name%>
</a>
</li>
<%})%>
</ul>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
const { Controller } = require('egg');
class NewsController extends Controller {
async index() {
const news = [
{
name: '魅族:高不成、低不就 15系列的求变生存恐怕不易',
url: 'https://baijia.baidu.com/s?id=1599513253231710086&wfr=pc&fr=idx_lst'
},
{
name: '从应届技术男到百度VP,这是低调到没百科的吴海锋首次受访',
url: 'https://baijia.baidu.com/s?id=1599508189171446369&wfr=pc&fr=idx_lst'
}
]
await this.ctx.render('news', { news });
}
}
module.exports = NewsController;
在实际应用中,Controller 一般不会自己产出数据,也不会包含复杂的逻辑,复杂的过程应抽象为业务逻辑层 Service。
config.default.js
exports.news = {
url: 'https://baijia.baidu.com'
}
const { Service } = require('egg');
class NewsService extends Service {
async list() {
const result = await this.ctx.curl(this.config.news.url);
let regexp = /<a href="(\/s\?id\=\d+[^"]+)".+>([\s\S]+?)<\/a>/g;
let news = [];
result.data.toString().replace(regexp, function () {
if (!(arguments[2].includes('img') || arguments[2].includes('查看详情'))) {
news.push({ url: 'https://baijia.baidu.com' + arguments[1], name: arguments[2] });
}
});
return news;
}
}
module.exports = NewsService;
//controller\news.js
const { Controller } = require('egg');
class NewsController extends Controller {
async index() {
const news = await this.ctx.service.news.list();
await this.ctx.render('news.ejs', { news });
}
}
module.exports = NewsController;
app/extend目录下提供扩展脚本即可app\extend\helper.js
const moment = require('moment');
moment.locale('zh-cn');
exports.relative = time => moment(new Date(time)).fromNow();
news.ejs
<%=helper.relative(item.time)%>
打印请求的处理时间
app\middleware\time.js
module.exports = (options, app) => {
return async function (ctx, next) {
const start = Date.now();
await next();
console.log(options.name + (Date.now() - start) + ' ms');
}
}
config.default.js
exports.middleware = [
'time'
]
exports.time = {
name: '总耗时:'
}
测试文件应该放在项目根目录下的 test 目录下,并以 test.js 为后缀名,即 {ROOT}/test/*/.test.js。 请注意是放在项目的根目录下,而非app目录下 // {ROOT}/test/app/middleware/robot.test.js
const { app, mock, assert } = require('egg-mock/bootstrap');
describe('test/app/middleware/robot.test.js', () => {
it('should block robot', () => {
return app.httpRequest()
.get('/')
.set('User-Agent', "Baiduspider")
.expect(403);
});
});