轻松搭建免运维即时通信应用:一顿饭的时间实现聊天小工具

引言

业余时间,闲来无事,想要利用云开发搭建一个即时通信的小工具?本文将带你一步步实现这个目标。一顿饭的时间,你的即时通信小工具就可以立马上线啦!

在本文中,我们将介绍如何利用腾讯云云开发快速搭建一个即时通信应用,解决长连接问题、实时推送功能、数据存储问题以及音视频问题。

准备工作

  • 首先,你需要在腾讯云官网开通 云开发 CloudBase 服务。届时,你将拥有云函数、数据库、云存储、登录、外网访问云函数等诸多能力和功能。这些将作为我们的后端服务基础。
  • 接下来,创建一个 Ant Design Pro 项目,用于开发前端界面。

实施过程

虽然 GitHub 上有很多优秀的库可以实现即时通信,但大多需要一定的理解成本和试错成本。本文遵循"时间就是金钱"的原则,希望能用最短的时间,搭建出一个基本可用的应用服务。正所谓"君子善假于物也"

云服务

创建数据库表

  1. 进入云开发控制台,在数据库页面新增一个「todo」的集合,用于存储我们的通信信息。
  2. 在「todo」集合中,我们会将一些基本字段,如:_id(主键,这个会自动生成)、content(消息内容)、timestamp(时间戳)、sender(发送者)等存储进去。这些字段将帮助我们存储和查询聊天记录。

Ant Design Pro 项目

使用 Ant Design Pro 搭建好基本的前端框架后,我们需要创建一个聊天界面。在聊天界面中,我们可以添加一个输入框(用于输入消息)、一个消息列表(用于展示聊天记录)以及一个发送按钮(用于发送消息)。

接下来,我们需要实现消息的发送和接收功能。为了实现这个功能,我们可以在前端项目中引入腾讯云云开发的 @cloudbase/js-sdk,并创建一个云开发实例。通过这个实例,我们可以调用云开发的接口,实现消息的发送和接收。

ts 复制代码
import cloudbase from '@cloudbase/js-sdk';

// 获取 云 sdk 实例
export const app = (): cloudbase.app.App =>
  cloudbase.init({
    env: {your-id}, // 您的环境id
  });

// 获取鉴权实例
export const getAuth = (): cloudbase.auth.App => {
  // 会话鉴权,失效策略
  const auth = app().auth({ persistence: 'session' });

  return auth;
};

// 获取数据库实例
export const getDB = (): cloudbase.database.App => {
  return app().database();
};

实现长连接

云开发数据库实例的 watch 接口,监听「todo」集合中的数据变化。当数据发生变化时,我们可以实时更新消息列表,从而实现消息的实时推送功能。前端 @cloudbase/js-sdk 能够直接操作数据库,安全又稳定,实现消息的发送

ts 复制代码
  const db = getDB();
  
  // 接收消息
  useEffect(() => {
    const _ = db.command;

    const watcher = db
      .collection('todo')
      .watch({
        onChange: (snapshot: any) => {
          // 当数据库有变化是,实时拉取的最新的数据
          setDataSource(snapshot.docs);
        },
        onError: (err: any) => {
          console.error('the watch closed because of error', err);
        },
      });

    return () => {
      watcher.close();
    };
  }, []);
ts 复制代码
const db = getDB();

/** 发送消息
 * 定义三种消息类型:image text aduio
 */
const onSend = (type, content) => {
  db.collection('todo').add({
   // 消息内容
   content,
   // 消息类型
   type
  });
}

当数据库中的数据发生变化时,监听接口会自动触发,从而实现数据的实时同步。从浏览器控制台打印的信息来看,@cloudbase/js-sdk 中实现的实时推送,也是基于 WebSocket 来实现

音频处理

音频的收集是借助 navigator.mediaDevices 实现,然后将收集到的音频数据存储到云上,并将云上的音频地址,保存到即时通信的数据表中(todo 集合)

可以看到 navigator.mediaDevices 的兼容性很不错,接下来是具体实现

tsx 复制代码
const AudioRecorder = ({ handleAudio = noop }) => {
  const [audioBlob, setAudioBlob] = useState(null);

  let mediaRecorder = useRef(null);
  let chunks = [];

  const startRecording = () => {
    // 创建音频
    navigator.mediaDevices
      .getUserMedia({ audio: true })
      .then((stream) => {
        mediaRecorder.current = new MediaRecorder(stream);
        mediaRecorder.current.addEventListener('dataavailable', (event) => {
          chunks.push(event.data);
        });
        mediaRecorder.current.addEventListener('stop', () => {
          const blob = new Blob(chunks, { type: 'audio/webm' });
          setAudioBlob(blob);
          chunks = [];
        });
        mediaRecorder.current.start();
      })
      .catch((error) => {
        console.error('无法访问麦克风', error);
      });
  };
  
  const stopRecording = () => {
    if (mediaRecorder.current?.state === 'recording') {
      mediaRecorder.current.stop();
 
      // 上传录音
      uploadAudio();
    }
  };
  
  // 将音频信息上传到云存储中,获取到音频地址
  const uploadAudio = async () => {
    if (audioBlob) {
      try {
        const res = await app().uploadFile({
          // 云存储的路径
          cloudPath: `im/${new Date().getTime()}.webm`,
          // 需要上传的文件,File 类型
          filePath: audioBlob,
        });
        
        // 处理音频地址,将音频地址保存到 todo 集合中
        onSend('audio', res?.download_url);
      } catch (error) { }
    }
  };

  return (
    <Button onClick={recording ? stopRecording : startRecording} />
  );
}

渲染音频消息很好实现,直接使用 <audio /> 标签

ts 复制代码
{type === 'audio' && <audio className="audio" controls src={content} />}

处理图片和表情

本地图片处理使用 antd 组件库的 Upload 组件

tsx 复制代码
const UploadButton: React.FC = ({ handleUpload = noop }) => {
    const props = {
        showUploadList: false,
        customRequest: async (file) => {
            const { name } = file.file;
            const res = await app().uploadFile({
                // 云存储的路径
                cloudPath: `im/${name}`,
                // 需要上传的文件,File 类型
                filePath: file.file,
            });

            file.onSuccess(res, file);
        },
        onChange(info) {
            if (info.file.status !== 'uploading') {
                console.log(info.file, info.fileList);
            }
            if (info.file.status === 'done') {
                const { download_url } = info.file.response;
                handleUpload(download_url);
            } else if (info.file.status === 'error') {
                message.error(`${info.file.name} file upload failed.`);
            }
        },
    };

    return (
        <Upload {...props}>
            <Button />
        </Upload>
    );
};

重点介绍一下表情的处理,表情又分为 emoji 和 gif 图

  • emoji (文本类型)
ts 复制代码
// 写个组件遍历这组数据就好,然后调用 onSend('text', emoji) 方法发送,注意这里是发送 text 类型的消息
const emojis = [
    '😀', '😁', '😂', '🤣', '😃', '😄', '😅', '😆', '😉', '😊', '😋', '😎', '😍', '😘', '😗', '😙', '😚', '🙂', '🤗', '🤔', '😐', '😑', '😶', '🙄', '😏', '😣', '😥', '😮', '🤐', '😯', '😪', '😫', '😴', '😌', '🤓', '😛', '😜', '😝', '🤤', '😒', '😓', '😔', '😕', '🙃', '🤑', '😲', '🙁', '😖', '😞', '😟', '😤', '😢', '😭', '😦', '😧', '😨', '😩', '😬', '😰', '😱', '😳', '😵', '😡', '😠', '🤬', '😷', '🤒', '🤕', '🤢', '🤮', '🤧', '😇', '🤠', '🤥', '🤫', '🤭', '🧐', '🤯', '🤪', '🥳', '🥴', '🥺', '🥰', '🥵', '🥶', '🥱', '🤎', '🤍'
]
  • gif 图

Giphy 是一个专门提供 GIF 动图的网站,用户可以在上面搜索、制作和分享 GIF 动图

关于gif图的实现思路,我们将借助 Giphy 平台。Giphy 提供了相关的 API,可以实现通过关键词来搜索出符合条件的 gif 图列表,进而实现 gif 图的渲染和选择。通过这种方式,我们可以丰富即时通信应用的功能,让用户在聊天过程中可以方便地发送和查看有趣的 GIF 动图。

为了实现这个功能,我们可以在前端项目中通过网络请求,并调用 Giphy 提供的搜索接口。当用户在聊天界面输入关键词并点击搜索按钮时,我们可以调用 Giphy 的搜索接口,获取相关的 gif 图列表。

ts 复制代码
// 获取gif
export const getGif = async (page: number = 0, perPage: number = 40, query = '') => {
  const repos = await request(`https://api.giphy.com/v1/gifs/search?api_key=${apiKey}&q=${query}&limit=${perPage}&offset=${page}`);

  return repos;
};

const onSearch = async (value) => {
    const { data = [] } = await getGif(0, 40, value)
    const gifs = data.map(item => item.images?.downsized?.url || '')
    // 更新 gif 图列表
    setList(gifs)
}

// 根据用户输入,调用 onSearch 方法
<Search placeholder="请输入" allowClear onSearch={onSearch} onPressEnter={onSearch} />

渲染图片消息使用 antd 组件库的 Image 组件

ts 复制代码
{type === 'image' && <Image width={200} src={content} />}

处理文本

用户输入完,点击发送按钮,调用 onSend('text', value) 上传就好

ts 复制代码
<TextArea
   value={value}
   autoSize={{ minRows: 1, maxRows: 6 }}
   onChange={onChange}
   onPressEnter={onPressEnter}
/>

处理浏览器通知

浏览器通知的功能需要用户手动开启,对于 Mac 用户来说,除了开启浏览器网页通知,还需要在 电脑系统设置 中,允许接受 浏览器的消息通知

当有新的消息过来时,我们希望浏览器的网页能发出通知提示,触达用户

ts 复制代码
// 显示通知的函数
function showNotification() {
  const title = 'Hello!'; // 自定义文案
  const options = {
    body: '提醒您喝水~.',
    icon: 'https://xxx', // 可选,通知图标的URL
  };

  const notification = new Notification(title, options);

  // 可选,处理通知点击事件
  notification.onclick = () => {
      notification.close()
  };
}

// 集成通知功能
export const notification = () => {
  // 检查浏览器是否支持通知
  if ('Notification' in window) {
    // 检查用户是否已授权通知
    if (Notification.permission === 'granted') {
      showNotification();
    } else if (Notification.permission !== 'denied') {
      // 请求用户授权
      Notification.requestPermission().then((permission) => {
        if (permission === 'granted') {
          showNotification();
        }
      });
    }
  } else {
    console.log('Your browser does not support notifications.');
  }
}

部署前端页面

可以将打包之后的前端资源,放到云开发的 静态网站托管 中,支持自定义域名

效果

我们看下 云存储数据库 的情况,我们可以通过控制台,对上传的数据进行 增删改查

  • 云存储

可以看到,上传的图片和音频资源,可以正常存储

  • 数据库

对于图片和音频资源,数据库存储的是网络地址,并且每条数据还 自动生成了 _id

总结

通过以上步骤,我们已经成功搭建了一个基本的即时通信应用。虽然这个应用还有很多可以优化的地方,但它已经具备了基本的通信功能。此外,它还 免运维。希望本文能帮助你快速搭建自己的即时通信小工具

相关推荐
崔庆才丨静觅4 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60615 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了5 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅5 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅6 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅6 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment6 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅6 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊6 小时前
jwt介绍
前端
爱敲代码的小鱼7 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax