0

0

LINE Bot 多消息类型回复:文本与贴图的组合发送指南

霞舞

霞舞

发布时间:2025-10-01 13:22:27

|

400人浏览过

|

来源于php中文网

原创

LINE Bot 多消息类型回复:文本与贴图的组合发送指南

本文旨在解决 LINE Bot 开发中,通过 Messaging API 组合发送文本消息和贴图时遇到的 400 Bad Request 错误。核心问题在于对同一 replyToken 进行多次 replyMessage 调用,而正确的做法是利用 API 支持在单次调用中发送一个消息数组,从而实现文本与贴图的无缝、原子性组合回复。

1. 问题背景与错误分析

在开发 line bot 时,常见需求是在接收到用户消息后,先通过外部 api(如 openai)生成回复文本,然后希望在文本之后再发送一个相关的贴图。初次尝试时,开发者可能倾向于分两步执行:首先调用 client.replymessage 发送文本,然后再次调用 client.replymessage 发送贴图。然而,这种做法通常会导致第二次 replymessage 调用失败,并返回 httperror: request failed with status code 400,错误信息中包含 bad request。

错误根源:replyToken 的一次性使用原则

LINE Messaging API 中的 replyToken 是一个非常关键的标识符,它代表了对特定用户事件的唯一回复机会。根据 LINE 的设计,每个 replyToken 只能被用于一次 replyMessage 调用。这意味着,一旦你使用 replyToken 发送了第一条消息(例如文本),该 replyToken 就会立即失效。随后的任何尝试使用同一个 replyToken 发送消息的请求都将被视为无效,从而导致 400 Bad Request 错误。

在原始的代码实现中,handleEvent 函数首先发送文本消息:

await client.replyMessage(event.replyToken, {
  type: 'text',
  text: reply
});

紧接着,它尝试发送贴图消息:

await sendStickerMessage(event.replyToken);

由于这两次调用使用了相同的 event.replyToken,第二次调用必然会失败。

2. 解决方案:一次性发送多条消息

LINE Messaging API 提供了在单次 replyMessage 调用中发送多条消息的能力。你只需要将所有要发送的消息(包括文本、贴图、图片、视频等)封装成一个数组,然后将这个数组作为 client.replyMessage 的第二个参数。

核心改动点:

Grokipedia
Grokipedia

xAI推出的AI在线百科全书

下载
  1. 合并消息发送逻辑: 将文本消息和贴图消息的构建与发送逻辑合并到一个函数中。
  2. 构建消息数组: 创建一个包含所有消息对象的数组。
  3. 单次 replyMessage 调用: 将消息数组传递给 client.replyMessage。

3. 实现步骤与代码示例

以下是基于原始问题和解决方案优化后的完整代码,展示了如何正确地在一次回复中发送文本和贴图。

'use strict';

// ########################################
//               初始化与配置
// ########################################

// 加载所需模块
const line = require('@line/bot-sdk');
const openai = require('openai');
const express = require('express');

const PORT = process.env.PORT || 3000;

// LINE Bot 配置
const config = {
    channelSecret: process.env.LINE_CHANNEL_SECRET || 'YOUR_CHANNEL_SECRET', // 建议从环境变量获取
    channelAccessToken: process.env.LINE_CHANNEL_ACCESS_TOKEN || 'YOUR_CHANNEL_ACCESS_TOKEN' // 建议从环境变量获取
};

// 创建 LINE Bot 客户端
const client = new line.Client(config);

// OpenAI GPT 配置
const gptConfig = new openai.Configuration({
    organization: process.env.OPENAI_ORGANIZATION_ID || "YOUR_ORGANIZATION_ID", // 建议从环境变量获取
    apiKey: process.env.OPENAI_API_KEY || 'YOUR_API_KEY', // 建议从环境变量获取
});
const gpt = new openai.OpenAIApi(gptConfig);

/**
 * 调用 OpenAI API 生成聊天回复
 * @param {Array} userMessages 用户消息数组,包含角色和内容
 * @returns {Promise} OpenAI API 的完成结果
 */
const makeCompletion = async (userMessages) => {
  const prompt = {
    role: 'system',
    content: '你是一位技艺精湛的鬼故事讲述者。请根据用户提供的关键词创作一个鬼故事。'
  };

  userMessages.unshift(prompt); // 将系统提示添加到消息列表的开头
  console.log('发送给 OpenAI 的消息:', userMessages);
  return await gpt.createChatCompletion({
    model: 'gpt-3.5-turbo',
    messages: userMessages,
    temperature: 0.2, // 降低温度以获得更稳定的故事
    n: 1
  });
};

/**
 * 处理 LINE 消息事件
 * @param {Object} event LINE Webhook 事件对象
 * @returns {Promise}
 */
async function handleEvent(event) {
  // 忽略非文本消息类型
  if (event.type !== 'message' || event.message.type !== 'text') {
    return Promise.resolve(null);
  }

  const userMessage = [
    {
      role: 'user',
      content: event.message.text
    }
  ];

  try {
    // 调用 ChatGPT API 生成回复
    const completion = await makeCompletion(userMessage);
    const replyText = completion.data.choices[0].message.content;

    // 使用 sendCombinedMessages 函数发送文本和贴图
    return sendCombinedMessages(event.replyToken, replyText);
  } catch (error) {
    console.error('处理消息时发生错误:', error);
    // 可以在这里发送一个错误提示给用户
    return Promise.resolve(null);
  }
}

/**
 * 发送组合消息(文本和贴图)
 * @param {string} replyToken 用于回复的令牌
 * @param {string} text 要发送的文本内容
 * @returns {Promise} LINE API 的回复结果
 */
async function sendCombinedMessages(replyToken, text) {
  try {
    const textMessage = {
      type: 'text',
      text: text
    };

    const stickerMessage = {
      type: 'sticker',
      packageId: '446', // 替换为你的贴图包 ID
      stickerId: '2027' // 替换为你的贴图 ID
    };

    // 将文本消息和贴图消息放入一个数组中,一次性发送
    return client.replyMessage(replyToken, [textMessage, stickerMessage]);
  } catch (error) {
    console.error('发送组合消息时发生错误:', error.message);
    if (error.response) {
      console.error('LINE API 错误详情:', error.response.data);
    }
    // 可以在这里根据错误类型进行更细致的处理
  }
}

// ########################################
//               Express 服务器设置
// ########################################

const app = express();

// 根路径 GET 请求,用于健康检查或简单提示
app.get('/', (req, res) => res.send('Hello LINE BOT! (HTTP GET)'));

// Webhook POST 请求处理
app.post('/webhook', line.middleware(config), (req, res) => {
  if (req.body.events.length === 0) {
    res.send('Hello LINE BOT! (HTTP POST)');
    console.log('收到验证事件!');
    return;
  } else {
    console.log('收到事件:', req.body.events);
  }

  // 并行处理所有事件
  Promise.all(
    req.body.events.map((event) => {
      if (event.type === 'message' && event.message.type === 'text') {
        return handleEvent(event);
      }
      // 如果需要处理其他消息类型(如贴图消息),可以在这里添加逻辑
      // else if (event.type === 'message' && event.message.type === 'sticker') {
      //   return handleMessageEvent(event); // 假设有处理贴图消息的函数
      // }
      else {
        return null;
      }
    })
  ).then((result) => res.json(result));
});

// 启动 Express 服务器
app.listen(PORT, () => {
  console.log(`Express 服务器正在端口 ${PORT} 上运行...`);
});

4. 关键代码变更与解释

  1. handleEvent 函数中的调用方式变更: 原始代码:

    await client.replyMessage(event.replyToken, { type: 'text', text: reply });
    await sendStickerMessage(event.replyToken);

    修改后:

    return sendCombinedMessages(event.replyToken, replyText);

    现在,handleEvent 不再直接发送消息,而是调用一个新的辅助函数 sendCombinedMessages,并将 replyText 传递过去,确保所有消息在一次 replyMessage 调用中完成。

  2. 新增 sendCombinedMessages 函数: 这个新函数负责构建一个消息数组,然后使用 client.replyMessage 一次性发送。

    async function sendCombinedMessages(replyToken, text) {
      try {
        const textMessage = {
          type: 'text',
          text: text
        };
    
        const stickerMessage = {
          type: 'sticker',
          packageId: '446', // 贴图包 ID
          stickerId: '2027' // 贴图 ID
        };
    
        // 将多个消息对象放入一个数组中
        return client.replyMessage(replyToken, [textMessage, stickerMessage]);
      } catch (error) {
        console.error('发送组合消息时发生错误:', error.message);
        if (error.response) {
          console.error('LINE API 错误详情:', error.response.data);
        }
      }
    }

    这里 [textMessage, stickerMessage] 就是一个消息数组,它包含了两种不同类型的消息。LINE API 会按数组顺序发送这些消息。

  3. 环境变量的使用: 为了提高安全性和可维护性,建议将敏感信息(如 channelSecret, channelAccessToken, OPENAI_API_KEY 等)存储在环境变量中,而不是硬编码在代码里。示例代码已更新为从 process.env 读取配置,并在未设置时提供默认占位符。

5. 注意事项

  • packageId 和 stickerId: 贴图的 packageId 和 stickerId 必须是有效的。你可以在 LINE Messaging API 文档的贴图列表页面(https://developers.line.biz/ja/docs/messaging-api/sticker-list/)找到可用的 ID。
  • 消息数量限制: replyMessage 调用一次最多可以发送 5 条消息。如果需要发送更多,你可能需要考虑使用 pushMessage 或其他策略。
  • 错误处理: 在实际生产环境中,需要更健壮的错误处理机制。当 LINE API 调用失败时,应捕获错误并记录详细信息,以便进行调试。error.response.data 通常包含 LINE API 返回的具体错误信息,这对于排查问题非常有帮助。
  • 异步操作: 确保所有异步操作都使用 await 或 .then() 正确处理,以避免未处理的 Promise 拒绝。
  • 代码组织: 随着 Bot 功能的增加,可以考虑将不同类型的消息处理逻辑或 API 调用封装成独立的模块,以提高代码的可读性和可维护性。

通过上述修改,你的 LINE Bot 将能够稳定地在一次回复中同时发送文本消息和贴图,提升用户体验,并避免因 replyToken 重复使用而导致的 400 错误。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
scripterror怎么解决
scripterror怎么解决

scripterror的解决办法有检查语法、文件路径、检查网络连接、浏览器兼容性、使用try-catch语句、使用开发者工具进行调试、更新浏览器和JavaScript库或寻求专业帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

228

2023.10.18

500error怎么解决
500error怎么解决

500error的解决办法有检查服务器日志、检查代码、检查服务器配置、更新软件版本、重新启动服务、调试代码和寻求帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

297

2023.10.25

mysql标识符无效错误怎么解决
mysql标识符无效错误怎么解决

mysql标识符无效错误的解决办法:1、检查标识符是否被其他表或数据库使用;2、检查标识符是否包含特殊字符;3、使用引号包裹标识符;4、使用反引号包裹标识符;5、检查MySQL的配置文件等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

183

2023.12.04

Python标识符有哪些
Python标识符有哪些

Python标识符有变量标识符、函数标识符、类标识符、模块标识符、下划线开头的标识符、双下划线开头、双下划线结尾的标识符、整型标识符、浮点型标识符等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

288

2024.02.23

java标识符合集
java标识符合集

本专题整合了java标识符相关内容,想了解更多详细内容,请阅读下面的文章。

259

2025.06.11

c++标识符介绍
c++标识符介绍

本专题整合了c++标识符相关内容,阅读专题下面的文章了解更多详细内容。

125

2025.08.07

promise的用法
promise的用法

“promise” 是一种用于处理异步操作的编程概念,它可以用来表示一个异步操作的最终结果。Promise 对象有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。Promise的用法主要包括构造函数、实例方法(then、catch、finally)和状态转换。

306

2023.10.12

html文本框类型介绍
html文本框类型介绍

html文本框类型有单行文本框、密码文本框、数字文本框、日期文本框、时间文本框、文件上传文本框、多行文本框等等。详细介绍:1、单行文本框是最常见的文本框类型,用于接受单行文本输入,用户可以在文本框中输入任意文本,例如用户名、密码、电子邮件地址等;2、密码文本框用于接受密码输入,用户在输入密码时,文本框中的内容会被隐藏,以保护用户的隐私;3、数字文本框等等。

406

2023.10.12

C++ 设计模式与软件架构
C++ 设计模式与软件架构

本专题深入讲解 C++ 中的常见设计模式与架构优化,包括单例模式、工厂模式、观察者模式、策略模式、命令模式等,结合实际案例展示如何在 C++ 项目中应用这些模式提升代码可维护性与扩展性。通过案例分析,帮助开发者掌握 如何运用设计模式构建高质量的软件架构,提升系统的灵活性与可扩展性。

14

2026.01.30

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WEB前端教程【HTML5+CSS3+JS】
WEB前端教程【HTML5+CSS3+JS】

共101课时 | 8.6万人学习

JS进阶与BootStrap学习
JS进阶与BootStrap学习

共39课时 | 3.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号