基于 Hapi 框架实现的在线聊天室技术分享

随着互联网的发展,聊天室已经成为了人们在线交流的重要方式。在前端领域,我们可以利用 Hapi 框架来实现一个在线聊天室。本文将详细介绍如何使用 Hapi 框架实现在线聊天室,并提供示例代码,帮助读者深入学习和实践。

Hapi 框架简介

Hapi 是一个 Node.js 的 Web 框架,它的设计目标是提供一种可靠且可扩展的服务端架构。Hapi 框架具有以下特点:

  • 高度模块化:Hapi 框架提供了丰富的插件和组件,可以轻松实现各种功能。
  • 非常灵活:Hapi 框架的路由系统非常灵活,可以根据需要进行定制。
  • 安全性高:Hapi 框架内置了许多安全特性,可以有效保护应用程序的安全性。

在线聊天室实现步骤

第一步:创建项目

首先,我们需要创建一个 Hapi 项目。可以使用 Hapi 的官方脚手架工具 hapi-cli 来快速创建项目:

npm install -g hapi-cli
hapi new-project chat-room
cd chat-room
npm install

第二步:安装依赖

在线聊天室需要使用到以下依赖:

  • hapi: Hapi 框架本身
  • hapi-auth-cookie: Hapi 的 Cookie 认证插件
  • nes: Hapi 的 WebSocket 插件

执行以下命令安装依赖:

npm install hapi hapi-auth-cookie nes

第三步:实现登录功能

在线聊天室需要实现用户登录功能。我们可以使用 Hapi 的 Cookie 认证插件 hapi-auth-cookie 来实现。

在项目的 index.js 文件中添加以下代码:

const Hapi = require('hapi');
const Joi = require('joi');
const HapiAuthCookie = require('hapi-auth-cookie');

const server = new Hapi.Server({
  port: 3000,
});

const users = [
  {
    id: 1,
    name: 'Alice',
    password: '123456',
  },
  {
    id: 2,
    name: 'Bob',
    password: '123456',
  },
];

const validate = async (request, session) => {
  const user = users.find(u => u.id === session.id);
  if (!user) {
    return { valid: false };
  }

  return { valid: true, credentials: user };
};

const init = async () => {
  await server.register(HapiAuthCookie);

  server.auth.strategy('session', 'cookie', {
    cookie: {
      name: 'sid',
      password: 'secret',
      isSecure: false,
    },
    redirectTo: '/login',
    validateFunc: validate,
  });

  server.route([
    {
      method: 'GET',
      path: '/login',
      handler: (request, h) => {
        return `
          <form method="post" action="/login">
            <div>
              <label>用户名</label>
              <input type="text" name="name">
            </div>
            <div>
              <label>密码</label>
              <input type="password" name="password">
            </div>
            <div>
              <button type="submit">登录</button>
            </div>
          </form>
        `;
      },
      options: {
        auth: false,
      },
    },
    {
      method: 'POST',
      path: '/login',
      handler: (request, h) => {
        const { name, password } = request.payload;
        const user = users.find(u => u.name === name && u.password === password);
        if (!user) {
          return h.redirect('/login?error=invalid');
        }

        request.cookieAuth.set({ id: user.id });
        return h.redirect('/');
      },
      options: {
        auth: false,
        validate: {
          payload: Joi.object({
            name: Joi.string().required(),
            password: Joi.string().required(),
          }),
        },
      },
    },
    {
      method: 'GET',
      path: '/',
      handler: (request, h) => {
        const user = request.auth.credentials;
        return `欢迎您,${user.name}!<a href="/logout">退出登录</a>`;
      },
      options: {
        auth: 'session',
      },
    },
    {
      method: 'GET',
      path: '/logout',
      handler: (request, h) => {
        request.cookieAuth.clear();
        return h.redirect('/');
      },
    },
  ]);

  await server.start();
  console.log(`Server running at: ${server.info.uri}`);
};

init();

这段代码实现了以下功能:

  • 定义了一个用户列表 users,包含每个用户的 idnamepassword
  • 定义了一个 validate 方法,用于验证用户是否登录
  • 注册了 hapi-auth-cookie 插件,并定义了 Cookie 认证策略
  • 定义了登录、退出登录和首页的路由

第四步:实现聊天室功能

在线聊天室需要使用到 WebSocket 技术。我们可以使用 Hapi 的 WebSocket 插件 nes 来实现。

在项目的 index.js 文件中添加以下代码:

const Hapi = require('hapi');
const Joi = require('joi');
const HapiAuthCookie = require('hapi-auth-cookie');
const Nes = require('nes');

const server = new Hapi.Server({
  port: 3000,
});

const users = [
  {
    id: 1,
    name: 'Alice',
    password: '123456',
  },
  {
    id: 2,
    name: 'Bob',
    password: '123456',
  },
];

const validate = async (request, session) => {
  const user = users.find(u => u.id === session.id);
  if (!user) {
    return { valid: false };
  }

  return { valid: true, credentials: user };
};

const init = async () => {
  await server.register([HapiAuthCookie, Nes]);

  server.auth.strategy('session', 'cookie', {
    cookie: {
      name: 'sid',
      password: 'secret',
      isSecure: false,
    },
    redirectTo: '/login',
    validateFunc: validate,
  });

  server.route([
    {
      method: 'GET',
      path: '/login',
      handler: (request, h) => {
        return `
          <form method="post" action="/login">
            <div>
              <label>用户名</label>
              <input type="text" name="name">
            </div>
            <div>
              <label>密码</label>
              <input type="password" name="password">
            </div>
            <div>
              <button type="submit">登录</button>
            </div>
          </form>
        `;
      },
      options: {
        auth: false,
      },
    },
    {
      method: 'POST',
      path: '/login',
      handler: (request, h) => {
        const { name, password } = request.payload;
        const user = users.find(u => u.name === name && u.password === password);
        if (!user) {
          return h.redirect('/login?error=invalid');
        }

        request.cookieAuth.set({ id: user.id });
        return h.redirect('/');
      },
      options: {
        auth: false,
        validate: {
          payload: Joi.object({
            name: Joi.string().required(),
            password: Joi.string().required(),
          }),
        },
      },
    },
    {
      method: 'GET',
      path: '/',
      handler: (request, h) => {
        const user = request.auth.credentials;
        return `
          <div>
            欢迎您,${user.name}!<a href="/logout">退出登录</a>
          </div>
          <div>
            <input type="text" id="message-input">
            <button type="button" id="send-button">发送</button>
          </div>
          <ul id="message-list"></ul>
          <script src="/nes.js"></script>
          <script>
            const client = new Nes.Client('ws://localhost:3000');
            client.connect().then(() => {
              client.subscribe('/chat', (message) => {
                const li = document.createElement('li');
                li.textContent = message;
                document.querySelector('#message-list').appendChild(li);
              });
            });

            document.querySelector('#send-button').addEventListener('click', () => {
              const input = document.querySelector('#message-input');
              const message = input.value.trim();
              if (message) {
                client.request({
                  method: 'POST',
                  path: '/chat',
                  payload: { message },
                });
                input.value = '';
              }
            });
          </script>
        `;
      },
      options: {
        auth: 'session',
      },
    },
    {
      method: 'GET',
      path: '/logout',
      handler: (request, h) => {
        request.cookieAuth.clear();
        return h.redirect('/');
      },
    },
    {
      method: 'POST',
      path: '/chat',
      handler: (request, h) => {
        const { message } = request.payload;
        server.publish('/chat', message);
        return { success: true };
      },
      options: {
        auth: 'session',
        validate: {
          payload: Joi.object({
            message: Joi.string().required(),
          }),
        },
      },
    },
  ]);

  await server.start();
  console.log(`Server running at: ${server.info.uri}`);
};

init();

这段代码实现了以下功能:

  • 注册了 nes 插件,用于实现 WebSocket 功能
  • 在首页中添加了一个文本框和一个发送按钮,用于发送消息
  • 定义了 /chat 路由,用于接收客户端发送的消息,并通过 server.publish 方法广播到所有客户端

总结

本文介绍了如何使用 Hapi 框架实现在线聊天室。通过本文的学习和实践,读者可以深入了解 Hapi 框架和 WebSocket 技术,掌握如何使用它们来实现实时通信功能。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/658e4982eb4cecbf2d4192cd


纠错
反馈