为收集到的种子信息搭建 Web 搜索服务
在前面的文章中,我们已经完成了种子数据的采集与存储。接下来,一个很自然的需求就是: 如何将这些数据通过 Web 服务的方式提供出来,支持搜索、查询和展示 。
本文将以 Egg.js v3.x 为基础,搭建一个简单但可扩展的 Web 搜索服务,为后续接入全文检索、分页查询、服务端渲染等能力打下基础。
为什么选择 Egg.js
本项目中我选择了 Egg.js v3.x 作为 Web 服务框架。Egg.js 是阿里开源的一套 Node.js 企业级框架,它以 Koa 作为底层内核,在其基础上进一步增强了:
- 统一的项目结构约定
- 插件化体系(数据库、模板、鉴权等)
- 完善的配置与环境隔离能力
- 成熟的工程化与最佳实践
官方文档地址: 👉 https://v3.eggjs.org/zh-CN/tutorials
当然,如果你更熟悉 NestJS、Express、Fastify,甚至是 Java / Go 框架 ,也完全可以用你熟悉的技术栈,整体思路是通用的。
初始化项目目录
首先,使用 Egg.js 官方脚手架初始化一个最精简的项目:
npm init egg --type=simplesimple 是 Egg.js 提供的 最小化模板 ,非常适合从零搭建接口服务或搜索服务,没有任何多余依赖。
初始化完成后,项目完整目录结构如下:
your-project-name/ # 项目根目录
├── app/ # 应用核心目录
│ ├── controller/ # 控制器目录(处理请求、返回响应)
│ │ └── home.js # 默认首页控制器
│ └── router.js # 路由配置文件(映射 URL 到控制器)
├── config/ # 配置文件目录
│ ├── config.default.js # 默认配置文件(所有环境通用)
│ ├── config.local.js # 本地开发环境配置(覆盖默认配置)
│ ├── config.prod.js # 生产环境配置(覆盖默认配置)
│ └── plugin.js # 插件配置文件(默认空)
├── test/ # 测试用例目录
│ └── app/
│ └── controller/
│ └── home.test.js # 默认首页控制器的测试用例
├── .autod.conf.js # autod 工具配置(管理依赖)
├── .eslintignore # ESLint 忽略文件配置
├── .eslintrc # ESLint 规则配置
├── .gitignore # Git 忽略文件配置
├── .travis.yml # Travis CI 持续集成配置(可选)
├── package.json # npm 包配置(依赖、脚本命令)
└── README.md # 项目说明文档核心目录与文件说明
1. app 目录(业务核心)
controller/home.js默认提供了一个HomeController,包含index方法,用于处理根路径/的请求,返回字符串hi, egg,可作为服务是否启动成功的验证入口。router.js定义路由映射规则,默认将GET /映射到home.index。
在后续搜索服务中,我们会在这里新增:
- 搜索控制器
- 列表页、详情页接口
- API 与页面渲染入口
2. config 目录(环境与插件配置)
config.default.js通用配置,如端口号(默认 7001)、应用名称、中间件等。config.local.js本地开发环境配置,通常用于:关闭 CSRF 校验
打开调试日志
使用本地数据库
config.prod.js生产环境配置,如:日志压缩
性能优化
安全策略
plugin.js用于启用 Egg.js 插件(数据库、模板引擎等)。
3. test 目录
Egg.js 内置了基于 egg-mocha 的测试体系,默认提供了一个示例测试用例,可直接通过:
npm test运行单元测试,对后续搜索接口非常有帮助。
4. package.json
包含:
- 核心依赖:
egg、egg-scripts - 开发依赖:
eslint、mocha - 启动命令:
npm run dev
小结
npm init egg --type=simple生成的是一个 极简、干净的 Egg.js 项目骨架- 核心关注点集中在
app(业务逻辑)和config(环境配置) - 默认集成了 ESLint 与测试框架,适合长期维护和扩展
安装数据库插件:egg-mysql
既然是搜索服务,就离不开数据查询。这里我选择 MySQL 作为存储方案,并使用官方推荐的 egg-mysql 插件。
官方文档: 👉 https://v3.eggjs.org/zh-CN/tutorials/mysql
数据库的表结构设计、种子数据的获取与保存,已在前面的文章中介绍过,这里不再重复。
安装插件
$ npm i --save egg-mysql启用插件
// config/plugin.js
exports.mysql = {
enable: true,
package: 'egg-mysql'
};配置数据库连接
在 config/config.${env}.js 中配置各环境数据库信息:
// config/config.${env}.js
exports.mysql = {
// 单数据库信息配置
client: {
// host
host: 'mysql.com',
// 端口号
port: '3306',
// 用户名
user: 'test_user',
// 密码
password: 'test_password',
// 数据库名
database: 'test'
},
// 是否加载到 app 上,默认开启
app: true,
// 是否加载到 agent 上,默认关闭
agent: false
};使用方式
await app.mysql.query(sql, values);如果是单实例数据库,可以直接通过 app.mysql 访问,非常方便。
egg-mysql底层基于ali-rds,如果你之前用过这个库,上手几乎没有学习成本。
安装模板引擎:egg-view-ejs
为了快速构建搜索结果页和详情页,我这里采用了 服务端渲染(SSR) 的方式,因此需要一个模板引擎。
我选择的是 EJS ,对应插件为 egg-view-ejs 。
官方文档: 👉 https://v3.eggjs.org/zh-CN/core/view
安装插件
$ npm i egg-view-ejs --save插件配置
// {app_root}/config/plugin.js
exports.ejs = {
enable: true,
package: 'egg-view-ejs',
};
// {app_root}/config/config.default.js
exports.view = {
mapping: {
'.ejs': 'ejs',
},
};创建模板文件
// app/view/hello.ejs
hello <%= data %>渲染模板
// app/controller/render.js
exports.ejs = async ctx => {
await ctx.render('hello.ejs', {
data: 'world',
});
};模板会被 编译并缓存 。如果你希望关闭缓存,可以设置:
config.ejs.cache = false在本地开发环境中,缓存默认是关闭的。
模板 include(模板拆分)
相对路径 include (相对于当前模板文件):
// app/view/a.ejs 引入 app/view/b.ejs
<% include('b.ejs') %>绝对路径 include (相对于 app/view 目录):
// app/view/home.ejs 引入 app/view/partial/menu.ejs
<% include('/partial/menu.ejs') %>使用 Layout 布局
可以为页面定义统一布局模板:
// app/view/layout.ejs
<% body %>// app/controller/render.js
exports.ejs = async ctx => {
const locals = {
data: 'world',
};
const viewOptions = {
layout: 'layout.ejs'
};
await ctx.render('hello.ejs', locals, viewOptions);
};这种方式非常适合构建 搜索列表页 + 公共头部 / 底部 的页面结构。
启动服务
最后,启动开发服务:
npm run dev如果终端没有报错,访问:
页面显示 hi, egg! ,说明 Egg.js Web 服务已经成功跑起来了。
总结与下一步
到这里,我们已经完成了:
- Egg.js 项目初始化
- 数据库插件集成
- 模板引擎配置
- Web 服务正常启动
下一篇文章 将重点介绍:
- 如何设计搜索接口
- 如何从数据库中分页查询种子数据
- 如何将搜索结果渲染成可用的页面
- 以及后续如何接入更高级的搜索能力(如全文检索)
如果你对 Egg.js + 搜索服务 + 数据工程 这条链路感兴趣,欢迎继续关注 👋




