Drogon 框架完全指南:C++ 后端开发的新选择

Drogon 框架完全指南:C++ 后端开发的新选择

目录

Drogon 框架完全指南:C++ 后端开发的新选择

Drogon 简介

环境搭建

快速入门:第一个 Drogon 应用

CMakeLists.txt

main.cpp

路由系统详解

routes.cpp

控制器模式

UserController.h

UserController.cpp

main.cpp

ORM 与数据库操作

首先创建模型类 User.h

DbUserController.h

DbUserController.cpp

main.cpp

中间件

LoggingMiddleware.h

LoggingMiddleware.cpp

AuthMiddleware.h

AuthMiddleware.cpp

main.cpp

配置文件

config.json

main.cpp

总结


Drogon(中文常被开发者亲切地称为 "龙")是一个基于 C++17 的高性能 HTTP/Web 框架,它让 C++ 开发 Web 应用变得简单而高效。本文将全面介绍 Drogon 框架的核心特性、使用方法和实战案例,帮助你快速上手这个强大的后端框架。

Drogon 简介

Drogon 是一个跨平台的 C++ 后端框架,具有以下特点:

  • 基于 C++17 标准,充分利用现代 C++ 特性
  • 异步非阻塞架构,性能卓越
  • 支持 HTTP 1.0/1.1,WebSocket
  • 内置 ORM 系统,轻松操作数据库
  • 支持 RESTful API 开发
  • 模块化设计,易于扩展
  • 轻量级,低资源消耗

环境搭建

首先,我们需要安装 Drogon 框架。以下是在 Ubuntu 系统上的安装步骤:

# 安装依赖 sudo apt-get install cmake g++ git libssl-dev zlib1g-dev libjsoncpp-dev # 克隆源码 git clone https://github.com/drogonframework/drogon.git cd drogon git submodule update --init # 编译安装 mkdir build cd build cmake .. make -j4 sudo make install 

快速入门:第一个 Drogon 应用

让我们创建一个最简单的 Drogon 应用,实现一个 "Hello World" 服务。

CMakeLists.txt

cmake_minimum_required(VERSION 3.10) project(hello_drogon) # 设置C++标准 set(CMAKE_CXX_STANDARD 17) # 查找Drogon库 find_package(Drogon REQUIRED) # 添加可执行文件 add_executable(hello_drogon main.cpp) # 链接Drogon库 target_link_libraries(hello_drogon PRIVATE Drogon::Drogon) 

main.cpp

#include <drogon/drogon.h> int main() { // 设置路由 drogon::app().registerHandler("/", [](const drogon::HttpRequestPtr& req, std::function<void (const drogon::HttpResponsePtr&)>&& callback) { auto resp = drogon::HttpResponse::newHttpResponse(); resp->setBody("Hello, Drogon!"); callback(resp); }); // 设置服务器监听地址和端口 drogon::app().addListener("0.0.0.0", 8080); // 启动服务器 std::cout << "Server running on http://localhost:8080" << std::endl; drogon::app().run(); return 0; } 

编译运行:

mkdir build && cd build cmake .. make ./hello_drogon 

现在访问http://localhost:8080,你将看到 "Hello, Drogon!" 的响应。

路由系统详解

Drogon 的路由系统非常灵活,支持多种路由方式:

routes.cpp

#include <drogon/drogon.h> #include <string> using namespace drogon; void initRoutes() { // 1. 基本路由 app().registerHandler("/", [](const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback) { auto resp = HttpResponse::newHttpResponse(); resp->setBody("<h1>Home Page</h1>"); resp->setContentTypeCode(CT_TEXT_HTML); callback(resp); }); // 2. 带参数的路由 app().registerHandler("/user/{name}", [](const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback, const std::string& name) { auto resp = HttpResponse::newHttpResponse(); resp->setBody("<h1>Hello, " + name + "!</h1>"); resp->setContentTypeCode(CT_TEXT_HTML); callback(resp); }); // 3. 正则表达式路由 app().registerHandler("/product/(\\d+)", [](const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback, const std::string& productId) { auto resp = HttpResponse::newHttpResponse(); resp->setBody("<h1>Product ID: " + productId + "</h1>"); resp->setContentTypeCode(CT_TEXT_HTML); callback(resp); }); // 4. 带HTTP方法限定的路由 app().registerHandler("/api/data", [](const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback) { auto resp = HttpResponse::newHttpResponse(); resp->setBody(R"({"status": "success", "data": "example data"})"); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); }, {HttpMethod::Get}); // 5. 路由组 auto userApi = app().createResourceGroup("user_api", "/api/user"); userApi->registerHandler("/profile", [](const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback) { auto resp = HttpResponse::newHttpResponse(); resp->setBody(R"({"name": "John Doe", "email": "[email protected]"})"); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); }, {HttpMethod::Get}); userApi->registerHandler("/update", [](const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback) { // 处理用户更新逻辑 auto resp = HttpResponse::newHttpResponse(); resp->setBody(R"({"status": "updated"})"); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); }, {HttpMethod::Post}); } int main() { app().addListener("0.0.0.0", 8080); initRoutes(); std::cout << "Server running on http://localhost:8080" << std::endl; app().run(); return 0; } 

控制器模式

对于大型应用,推荐使用控制器模式来组织代码:

UserController.h

#pragma once #include <drogon/HttpController.h> using namespace drogon; class UserController : public HttpController<UserController> { public: METHOD_LIST_BEGIN // 注册路由 ADD_METHOD_TO(UserController::getUser, "/user/{id}", HttpMethod::Get); ADD_METHOD_TO(UserController::createUser, "/user", HttpMethod::Post); ADD_METHOD_TO(UserController::updateUser, "/user/{id}", HttpMethod::Put); ADD_METHOD_TO(UserController::deleteUser, "/user/{id}", HttpMethod::Delete); METHOD_LIST_END // 控制器方法 void getUser(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback, int id) const; void createUser(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback) const; void updateUser(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback, int id) const; void deleteUser(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback, int id) const; }; 

UserController.cpp

#include "UserController.h" #include <nlohmann/json.hpp> using json = nlohmann::json; void UserController::getUser(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback, int id) const { // 模拟从数据库获取用户 json user = { {"id", id}, {"name", "John Doe"}, {"email", "[email protected]"} }; auto resp = HttpResponse::newHttpResponse(); resp->setBody(user.dump()); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); } void UserController::createUser(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback) const { // 解析请求体 auto jsonBody = req->getJsonObject(); if (!jsonBody) { auto resp = HttpResponse::newHttpResponse(); resp->setStatusCode(k400BadRequest); resp->setBody(R"({"error": "Invalid request body"})"); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); return; } // 模拟创建用户 json response = { {"status", "success"}, {"message", "User created"}, {"userId", 123} // 假设生成的用户ID }; auto resp = HttpResponse::newHttpResponse(); resp->setStatusCode(k201Created); resp->setBody(response.dump()); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); } void UserController::updateUser(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback, int id) const { // 模拟更新用户 json response = { {"status", "success"}, {"message", "User updated"}, {"userId", id} }; auto resp = HttpResponse::newHttpResponse(); resp->setBody(response.dump()); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); } void UserController::deleteUser(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback, int id) const { // 模拟删除用户 json response = { {"status", "success"}, {"message", "User deleted"}, {"userId", id} }; auto resp = HttpResponse::newHttpResponse(); resp->setBody(response.dump()); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); } 

main.cpp

#include <drogon/drogon.h> #include "UserController.h" int main() { // 设置服务器端口 drogon::app().addListener("0.0.0.0", 8080); // 注册控制器 drogon::app().registerController(std::make_shared<UserController>()); // 运行应用 std::cout << "Server running on http://localhost:8080" << std::endl; drogon::app().run(); return 0; } 

ORM 与数据库操作

Drogon 内置了强大的 ORM 系统,支持多种数据库。以下是使用 ORM 操作 MySQL 的示例:

首先创建模型类 User.h

#pragma once #include <drogon/orm/ORM.h> #include <string> using namespace drogon::orm; class User { public: // 定义表结构 std::string name; std::string email; int age = 0; std::string created_at; // 映射到数据库表 DROGON_MAPPING(User, (name, VARCHAR, 50) (email, VARCHAR, 100, UNIQUE) (age, INT) (created_at, TIMESTAMP) ) }; 

DbUserController.h

#pragma once #include <drogon/HttpController.h> #include "User.h" using namespace drogon; class DbUserController : public HttpController<DbUserController> { public: METHOD_LIST_BEGIN ADD_METHOD_TO(DbUserController::getAllUsers, "/db/users", HttpMethod::Get); ADD_METHOD_TO(DbUserController::getUserById, "/db/users/{id}", HttpMethod::Get); ADD_METHOD_TO(DbUserController::createUser, "/db/users", HttpMethod::Post); METHOD_LIST_END void getAllUsers(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback) const; void getUserById(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback, int id) const; void createUser(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback) const; }; 

DbUserController.cpp

#include "DbUserController.h" #include <nlohmann/json.hpp> #include <drogon/drogon.h> using json = nlohmann::json; using namespace drogon::orm; void DbUserController::getAllUsers(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback) const { // 获取数据库客户端 auto client = app().getDbClient(); // 查询所有用户 client->execSqlAsync( "SELECT * FROM users", [callback](const Result& result) { json response; for (const auto& row : result) { json user; user["id"] = row["id"].as<int>(); user["name"] = row["name"].as<std::string>(); user["email"] = row["email"].as<std::string>(); user["age"] = row["age"].as<int>(); user["created_at"] = row["created_at"].as<std::string>(); response.push_back(user); } auto resp = HttpResponse::newHttpResponse(); resp->setBody(response.dump()); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); }, [callback](const DrogonDbException& e) { auto resp = HttpResponse::newHttpResponse(); resp->setStatusCode(k500InternalServerError); resp->setBody(json{{"error", e.base().what()}}.dump()); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); } ); } void DbUserController::getUserById(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback, int id) const { auto client = app().getDbClient(); client->execSqlAsync( "SELECT * FROM users WHERE id = $1", [callback](const Result& result) { auto resp = HttpResponse::newHttpResponse(); if (result.size() == 0) { resp->setStatusCode(k404NotFound); resp->setBody(json{{"error", "User not found"}}.dump()); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); return; } const auto& row = result[0]; json user; user["id"] = row["id"].as<int>(); user["name"] = row["name"].as<std::string>(); user["email"] = row["email"].as<std::string>(); user["age"] = row["age"].as<int>(); user["created_at"] = row["created_at"].as<std::string>(); resp->setBody(user.dump()); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); }, [callback](const DrogonDbException& e) { auto resp = HttpResponse::newHttpResponse(); resp->setStatusCode(k500InternalServerError); resp->setBody(json{{"error", e.base().what()}}.dump()); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); }, id ); } void DbUserController::createUser(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback) const { auto jsonBody = req->getJsonObject(); if (!jsonBody || !jsonBody->isMember("name") || !jsonBody->isMember("email")) { auto resp = HttpResponse::newHttpResponse(); resp->setStatusCode(k400BadRequest); resp->setBody(json{{"error", "Missing required fields"}}.dump()); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); return; } std::string name = (*jsonBody)["name"].asString(); std::string email = (*jsonBody)["email"].asString(); int age = jsonBody->isMember("age") ? (*jsonBody)["age"].asInt() : 0; auto client = app().getDbClient(); client->execSqlAsync( "INSERT INTO users (name, email, age, created_at) VALUES ($1, $2, $3, NOW()) RETURNING id", [callback](const Result& result) { auto resp = HttpResponse::newHttpResponse(); resp->setStatusCode(k201Created); resp->setBody(json{ {"status", "success"}, {"message", "User created"}, {"userId", result[0]["id"].as<int>()} }.dump()); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); }, [callback](const DrogonDbException& e) { auto resp = HttpResponse::newHttpResponse(); resp->setStatusCode(k500InternalServerError); resp->setBody(json{{"error", e.base().what()}}.dump()); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); }, name, email, age ); } 

main.cpp

#include <drogon/drogon.h> #include "DbUserController.h" int main() { // 配置数据库连接 drogon::app().createDbClient("mysql", "localhost", 3306, "username", "password", "test_db"); // 设置服务器端口 drogon::app().addListener("0.0.0.0", 8080); // 注册控制器 drogon::app().registerController(std::make_shared<DbUserController>()); // 运行应用 std::cout << "Server running on http://localhost:8080" << std::endl; drogon::app().run(); return 0; } 

中间件

Drogon 支持中间件,可以用于实现认证、日志、缓存等功能:

LoggingMiddleware.h

#pragma once #include <drogon/HttpMiddleware.h> using namespace drogon; class LoggingMiddleware : public HttpMiddleware<LoggingMiddleware> { public: void handler(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback, NextHandler&& next) override; }; 

LoggingMiddleware.cpp

#include "LoggingMiddleware.h" #include <chrono> #include <ctime> #include <iomanip> #include <sstream> void LoggingMiddleware::handler(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback, NextHandler&& next) { // 记录请求开始时间 auto start = std::chrono::high_resolution_clock::now(); // 创建自定义回调来记录响应信息 auto newCallback = [callback, start, req](const HttpResponsePtr& resp) { // 计算请求处理时间 auto end = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start); // 格式化时间 auto now = std::chrono::system_clock::now(); std::time_t now_time = std::chrono::system_clock::to_time_t(now); std::tm* tm = std::localtime(&now_time); std::stringstream ss; ss << std::put_time(tm, "%Y-%m-%d %H:%M:%S"); // 打印日志 std::cout << "[" << ss.str() << "] " << req->methodString() << " " << req->path() << " " << resp->statusCode() << " " << duration.count() << "µs" << std::endl; // 调用原始回调 callback(resp); }; // 调用下一个中间件或处理程序 next(req, std::move(newCallback)); } 

AuthMiddleware.h

#pragma once #include <drogon/HttpMiddleware.h> using namespace drogon; class AuthMiddleware : public HttpMiddleware<AuthMiddleware> { public: void handler(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback, NextHandler&& next) override; }; 

AuthMiddleware.cpp

#include "AuthMiddleware.h" #include <nlohmann/json.hpp> using json = nlohmann::json; void AuthMiddleware::handler(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr&)>&& callback, NextHandler&& next) { // 检查Authorization头 auto authHeader = req->getHeader("Authorization"); if (!authHeader || authHeader->empty()) { auto resp = HttpResponse::newHttpResponse(); resp->setStatusCode(k401Unauthorized); resp->setBody(json{{"error", "Authorization header missing"}}.dump()); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); return; } // 简单验证令牌 (实际应用中应该更复杂) if (*authHeader != "Bearer secret_token") { auto resp = HttpResponse::newHttpResponse(); resp->setStatusCode(k403Forbidden); resp->setBody(json{{"error", "Invalid or expired token"}}.dump()); resp->setContentTypeCode(CT_APPLICATION_JSON); callback(resp); return; } // 验证通过,调用下一个中间件或处理程序 next(req, std::move(callback)); } 

main.cpp

#include <drogon/drogon.h> #include "AuthMiddleware.h" #include "LoggingMiddleware.h" int main() { // 全局中间件 - 所有请求都会经过日志中间件 drogon::app().registerMiddleware(std::make_shared<LoggingMiddleware>()); // 路由级中间件 - 只有/api/protected/*路径会经过认证中间件 auto protectedApi = drogon::app().createResourceGroup("protected_api", "/api/protected") .addMiddleware(std::make_shared<AuthMiddleware>()); // 受保护的路由 protectedApi->registerHandler("/data", [](const drogon::HttpRequestPtr& req, std::function<void (const drogon::HttpResponsePtr&)>&& callback) { auto resp = drogon::HttpResponse::newHttpResponse(); resp->setBody(R"({"data": "This is protected data"})"); resp->setContentTypeCode(drogon::CT_APPLICATION_JSON); callback(resp); }, {drogon::HttpMethod::Get}); // 公开路由 drogon::app().registerHandler("/public/data", [](const drogon::HttpRequestPtr& req, std::function<void (const drogon::HttpResponsePtr&)>&& callback) { auto resp = drogon::HttpResponse::newHttpResponse(); resp->setBody(R"({"data": "This is public data"})"); resp->setContentTypeCode(drogon::CT_APPLICATION_JSON); callback(resp); }, {drogon::HttpMethod::Get}); // 启动服务器 drogon::app().addListener("0.0.0.0", 8080); std::cout << "Server running on http://localhost:8080" << std::endl; drogon::app().run(); return 0; } 

配置文件

对于复杂应用,推荐使用配置文件来配置 Drogon 应用:

config.json

{ "listeners": [ { "address": "0.0.0.0", "port": 8080, "https": false } ], "db_clients": [ { "name": "default", "type": "mysql", "host": "localhost", "port": 3306, "dbname": "test_db", "user": "username", "password": "password", "connections": 10 } ], "app": { "name": "My Drogon App", "description": "A sample application using Drogon framework", "version": "1.0.0" }, "log": { "level": "info", "log_to_console": true, "log_to_file": true, "log_file": "app.log" }, "workers": 4 } 

main.cpp

#include <drogon/drogon.h> int main() { // 从配置文件加载配置 drogon::app().loadConfigFile("config.json"); // 注册路由和控制器... drogon::app().registerHandler("/", [](const drogon::HttpRequestPtr& req, std::function<void (const drogon::HttpResponsePtr&)>&& callback) { auto resp = drogon::HttpResponse::newHttpResponse(); resp->setBody("Hello from configured app!"); callback(resp); }); // 运行应用 std::cout << "Server running with config" << std::endl; drogon::app().run(); return 0; } 

总结

Drogon 框架为 C++ 开发者提供了一个现代化、高性能的后端开发解决方案。它充分利用了 C++17 的新特性,同时提供了简洁易用的 API,让开发者能够快速构建高性能的 Web 应用和 API 服务。

本文介绍了 Drogon 的核心功能,包括路由系统、控制器模式、ORM 数据库操作、中间件和配置文件等。通过这些功能,你可以构建出结构清晰、性能卓越的 C++ 后端应用。

Drogon 的学习曲线虽然比一些脚本语言框架陡峭,但对于需要高性能和低资源消耗的场景,它无疑是一个值得深入学习和使用的优秀框架。

如果你想了解更多关于 Drogon 的信息,可以访问其官方网站和 GitHub 仓库:

Read more

安装 启动 使用 Neo4j的超详细教程

安装 启动 使用 Neo4j的超详细教程

最近在做一个基于知识图谱的智能生成项目。需要用到Neo4j图数据库。写这篇文章记录一下Neo4j的安装及其使用。 一.Neo4j的安装 1.首先安装JDK,配环境变量。(参照网上教程,很多) Neo4j是基于Java的图形数据库,运行Neo4j需要启动JVM进程,因此必须安装JAVA SE的JDK。从Oracle官方网站下载 Java SE JDK。我使用的版本是JDK1.8 2.官网上安装neo4j。 官方网址:https://neo4j.com/deployment-center/  在官网上下载对应版本。Neo4j应用程序有如下主要的目录结构: bin目录:用于存储Neo4j的可执行程序; conf目录:用于控制Neo4j启动的配置文件; data目录:用于存储核心数据库文件; plugins目录:用于存储Neo4j的插件; 3.配置环境变量 创建主目录环境变量NEO4J_HOME,并把主目录设置为变量值。复制具体的neo4j文件地址作为变量值。 配置文档存储在conf目录下,Neo4j通过配置文件neo4j.conf控制服务器的工作。默认情况下,不需

企业微信群机器人Webhook配置全攻略:从创建到发送消息的完整流程

企业微信群机器人Webhook配置全攻略:从创建到发送消息的完整流程 在数字化办公日益普及的今天,企业微信作为国内领先的企业级通讯工具,其群机器人功能为团队协作带来了极大的便利。本文将手把手教你如何从零开始配置企业微信群机器人Webhook,实现自动化消息推送,提升团队沟通效率。 1. 准备工作与环境配置 在开始创建机器人之前,需要确保满足以下基本条件: * 企业微信账号:拥有有效的企业微信管理员或成员账号 * 群聊条件:至少包含3名成员的群聊(这是创建机器人的最低人数要求) * 网络环境:能够正常访问企业微信服务器 提示:如果是企业管理员,建议先在"企业微信管理后台"确认机器人功能是否已对企业开放。某些企业可能出于安全考虑会限制此功能。 2. 创建群机器人 2.1 添加机器人到群聊 1. 打开企业微信客户端,进入目标群聊 2. 点击右上角的群菜单按钮(通常显示为"..."或"⋮") 3. 选择"添加群机器人"选项 4.

Flowise物联网融合:与智能家居设备联动的应用设想

Flowise物联网融合:与智能家居设备联动的应用设想 1. Flowise:让AI工作流变得像搭积木一样简单 Flowise 是一个真正把“AI平民化”落地的工具。它不像传统开发那样需要写几十行 LangChain 代码、配置向量库、调试提示词模板,而是把所有这些能力打包成一个个可拖拽的节点——就像小时候玩乐高,你不需要懂塑料怎么合成,只要知道哪块该拼在哪,就能搭出一座城堡。 它诞生于2023年,短短一年就收获了45.6k GitHub Stars,MIT协议开源,意味着你可以放心把它用在公司内部系统里,甚至嵌入到客户交付的产品中,完全不用担心授权问题。最打动人的不是它的技术多炫酷,而是它真的“不挑人”:产品经理能搭出知识库问答机器人,运营同学能配出自动抓取竞品文案的Agent,连刚学Python两周的实习生,也能在5分钟内跑通一个本地大模型的RAG流程。 它的核心逻辑很朴素:把LangChain里那些抽象概念——比如LLM调用、文档切分、向量检索、工具调用——变成画布上看得见、摸得着的方块。你拖一个“Ollama LLM”节点,再拖一个“Chroma Vector

OpenClaw配置Bot接入飞书机器人+Kimi2.5

OpenClaw配置Bot接入飞书机器人+Kimi2.5

上一篇文章写了Ubuntu_24.04下安装OpenClaw的过程,这篇文档记录一下接入飞书机器+Kimi2.5。 准备工作 飞书 创建飞书机器人 访问飞书开放平台:https://open.feishu.cn/app,点击创建应用: 填写应用名称和描述后就直接创建: 复制App ID 和 App Secret 创建成功后,在“凭证与基础信息”中找到 App ID 和 App Secret,把这2个信息复制记录下来,后面需要配置到openclaw中 配置权限 点击【权限管理】→【开通权限】 或使用【批量导入/导出权限】,选择导入,输入以下内容,如下图 点击【下一步,确认新增权限】即可开通所需要的权限。 配置事件与回调 说明:这一步的配置需要先讲AppId和AppSecret配置到openclaw成功之后再设置订阅方式,