Hapi 是一款优秀的 Node.js Web 框架,它采用了插件化的设计思想,可以通过组合各种插件快速搭建复杂的 Web 应用程序。在 Hapi 中,你可以使用路由来管理 URL 地址和处理请求,同时你还可以使用 Hapi 的插件来增强应用程序的功能。Hapi 插件可以提供很多种服务,包括路由处理、模板渲染、数据库操作、鉴权和安全等等。借助 Hapi 插件,我们可以更加高效和灵活地构建 Web 应用程序。
本文将介绍如何使用 Hapi Plug-Ins 构建基于路由的应用程序,重点讲解路由的处理和插件的使用。我们将以 Blog 为例来演示,该应用程序有以下几个功能:
- 主页展示博客文章列表。
- 查看博客文章详情页面。
- 创建、编辑和删除博客文章。
搭建项目
首先,我们需要初始化 Node.js 项目并安装 Hapi 和 MongoDB 驱动:
$ mkdir hapi-blog $ cd hapi-blog $ npm init -y $ npm install hapi mongodb --save
接下来,创建一个启动服务的主文件 server.js,代码如下:
// www.javascriptcn.com code example
const Hapi = require('@hapi/hapi');
const init = async () => {
const server = Hapi.server({
port: process.env.PORT || 3000,
host: 'localhost',
routes: {
cors: true
}
});
// 在这里注册插件
await server.start();
console.log(`Server running at: ${server.info.uri}`);
};
process.on('unhandledRejection', (err) => {
console.log(err);
process.exit(1);
});
init();在这个主文件中,我们通过 Hapi.server 方法创建了一个服务器实例,同时配置了服务器的一些选项。其中,port 表示服务器监听的端口号,host 表示服务器监听的主机地址,routes 表示服务器的路由选项,cors 为 true 表示允许跨域访问。接着,我们需要在这个文件中注册插件,并启动服务器。
路由管理
在 Hapi 中,路由是一个比较重要的概念。一个路由可以定义 URL 地址和处理请求的函数。在这里,我们需要创建三个路由,分别用于主页展示博客文章列表、查看博客文章详情和创建 / 编辑 / 删除博客文章。
首页路由
首先,我们需要创建一个获取博客文章列表的路由,代码如下:
// www.javascriptcn.com code example
server.route({
method: 'GET',
path: '/',
handler: async (request, h) => {
// 获取博客文章列表
const articles = [];
return h.view('index', { articles });
}
});在这个路由中,我们定义了一个 GET 方法,表示这个路由用于获取数据。path 表示路由的 URL 地址,handler 是一个处理请求的函数,它会返回通过 h.view 方法渲染的 HTML 页面。
文章详情路由
接着,我们需要创建一个获取博客文章详情的路由,代码如下:
// www.javascriptcn.com code example
server.route({
method: 'GET',
path: '/article/{id}',
handler: async (request, h) => {
const { id } = request.params;
// 根据 id 获取文章详情
const article = null;
return h.view('article', { article });
}
});在这个路由中,我们同样定义了一个 GET 方法,同时增加了一个路径参数 id,用于标识文章的唯一 ID。在 handler 方法中,我们通过 request.params 获取该参数,在根据 ID 获取文章详情。最后,我们也是通过 h.view 方法渲染 HTML 页面。
编辑 / 创建 / 删除文章路由
最后,我们需要创建三个路由,用于编辑、创建和删除博客文章。
// www.javascriptcn.com code example
server.route([
{
method: 'GET',
path: '/edit/{id}',
handler: async (request, h) => {
const { id } = request.params;
// 根据 id 获取文章详情
const article = null;
return h.view('edit', { article });
}
},
{
method: 'POST',
path: '/edit',
handler: async (request, h) => {
const { id, title, content } = request.payload;
// 更新文章
const article = null;
return h.redirect('/');
}
},
{
method: 'POST',
path: '/create',
handler: async (request, h) => {
const { title, content } = request.payload;
// 创建文章
const article = null;
return h.redirect('/');
}
},
{
method: 'GET',
path: '/delete/{id}',
handler: async (request, h) => {
const { id } = request.params;
// 根据 id 删除文章
const result = null;
return h.redirect('/');
}
}
]);在这几个路由中,我们用到了不同的 HTTP 方法,分别用于编辑文章(GET)、更新文章(POST)、创建文章(POST)和删除文章(GET)。其中,request.payload 表示请求的数据,比如 POST 请求提交的表单数据。在这里,我们用到了 h.redirect 方法,它会将路由导向到指定的页面。
插件使用
在 Hapi 中,插件是一个比较重要的概念。Hapi 内置了很多插件,同时你也可以通过 npm 下载其他插件。插件可以提供 Hapi 功能或扩展应用程序能力。
在这里,我们将使用 Vision 插件和 Inert 插件分别提供模板渲染和静态文件服务功能。我们先来安装这两个插件:
$ npm install @hapi/vision @hapi/inert --save
接着,在 server.js 中引入这两个插件并注册:
// www.javascriptcn.com code example
const Hapi = require('@hapi/hapi');
const Vision = require('@hapi/vision');
const Inert = require('@hapi/inert');
const init = async () => {
const server = Hapi.server({
port: process.env.PORT || 3000,
host: 'localhost',
routes: {
cors: true
}
});
await server.register(Vision);
await server.register(Inert);
// 配置视图引擎
server.views({
engines: { pug: require('pug') },
relativeTo: __dirname,
path: 'views'
});
// 在这里注册路由
await server.start();
console.log(`Server running at: ${server.info.uri}`);
};在这个文件中,我们引入了 Vision 和 Inert 插件,并在 async 函数中通过 server.register 注册它们。同时,我们配置了视图引擎的选项,使用了 pug 模板引擎,并设置了 views 文件夹为视图的根目录。
示例代码
最后,我们将所有代码结合起来,形成完整的 Blog 应用程序。注意,在这个示例代码中,我们使用了 MongoDB 作为数据库,需要配置 MongoDB 数据库信息。
// www.javascriptcn.com code example
const Hapi = require('@hapi/hapi');
const Vision = require('@hapi/vision');
const Inert = require('@hapi/inert');
const MongoClient = require('mongodb').MongoClient;
const ObjectID = require('mongodb').ObjectID;
const init = async () => {
const mongoURL = 'mongodb://localhost:27017';
const dbName = 'blog';
const connection = await MongoClient.connect(mongoURL, { useNewUrlParser: true });
const db = connection.db(dbName);
const server = Hapi.server({
port: process.env.PORT || 3000,
host: 'localhost',
routes: {
cors: true
}
});
await server.register(Vision);
await server.register(Inert);
server.views({
engines: { pug: require('pug') },
relativeTo: __dirname,
path: 'views'
});
server.route([
{
method: 'GET',
path: '/',
handler: async (request, h) => {
const articles = await db.collection('articles').find().toArray();
return h.view('index', { articles });
}
},
{
method: 'GET',
path: '/article/{id}',
handler: async (request, h) => {
const { id } = request.params;
const article = await db.collection('articles').findOne({ _id: ObjectID(id) });
return h.view('article', { article });
}
},
{
method: 'GET',
path: '/edit/{id}',
handler: async (request, h) => {
const { id } = request.params;
const article = await db.collection('articles').findOne({ _id: ObjectID(id) });
return h.view('edit', { article });
}
},
{
method: 'POST',
path: '/edit',
handler: async (request, h) => {
const { id, title, content } = request.payload;
const result = await db.collection('articles').updateOne({ _id: ObjectID(id) }, { $set: { title, content } });
return h.redirect('/');
}
},
{
method: 'POST',
path: '/create',
handler: async (request, h) => {
const { title, content } = request.payload;
const result = await db.collection('articles').insertOne({ title, content });
return h.redirect('/');
}
},
{
method: 'GET',
path: '/delete/{id}',
handler: async (request, h) => {
const { id } = request.params;
const result = await db.collection('articles').deleteOne({ _id: ObjectID(id) });
return h.redirect('/');
}
},
{
method: 'GET',
path: '/public/{param*}',
handler: {
directory: {
path: 'public'
}
}
}
]);
await server.start();
console.log(`Server running at: ${server.info.uri}`);
};
process.on('unhandledRejection', (err) => {
console.log(err);
process.exit(1);
});
init();在这个示例代码中,我们首先连接 MongoDB 数据库并获取 db 对象,然后在注册插件和路由之后,通过 db 对象进行数据查询和更新操作。同时,我们也增加了静态文件服务的路由,用于访问 public 文件夹中的静态资源。
你可以通过运行 node server.js 启动服务器,打开浏览器访问 http://localhost:3000/,查看 Blog 的效果。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67d7cb08a941bf7134df3bec