发送webhook到飞书机器人

发送webhook到飞书机器人

发送webhook到飞书机器人

参考链接 自定义机器人使用指南

创建自定义机器人

  1. 邀请自定义机器人进群。
  2. 获取签名校验
    在 安全设置 区域,选择 签名校验。

获取自定义机器人的 webhook 地址
机器人对应的 webhook 地址 格式如下:
https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxxxxxxxxxxxxx
请妥善保存好此 webhook 地址,不要公布在 Gitlab、博客等可公开查阅的网站上,避免地址泄露后被恶意调用发送垃圾消息。

在这里插入图片描述

设置自定义机器人的头像、名称与描述,并点击 添加。

在这里插入图片描述

在 群机器人 界面点击 添加机器人。在 添加机器人 对话框,找到并点击 自定义机器人。

在这里插入图片描述

在右侧 设置 界面,点击 群机器人。

在这里插入图片描述

进入目标群组,在群组右上角点击更多按钮,并点击 设置。

在这里插入图片描述

选择签名校验后,系统已默认提供了一个秘钥。你也可以点击 重置,更换秘钥。

在这里插入图片描述

使用java发送http post到自定义机器人

  1. 计算签名校验,参考官方文档的SignDemo.java,自定义一个签名函数
privatestaticStringgenSign(String secret,long timestamp)throwsNoSuchAlgorithmException,InvalidKeyException{//把timestamp+"\n"+密钥当做签名字符串String stringToSign = timestamp +"\n"+ secret;//使用HmacSHA256算法计算签名Mac mac =Mac.getInstance("HmacSHA256"); mac.init(newSecretKeySpec(stringToSign.getBytes(StandardCharsets.UTF_8),"HmacSHA256"));byte[] signData = mac.doFinal(newbyte[]{});returnnewString(Base64.encodeBase64(signData));}
  1. 计算时间戳
    需要注意的是,时间戳是以秒为单位的,并且要配置时区,不可直接使用System.currentTimeMillis()/1000来计算秒值
long seconds =LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().getEpochSecond();
  1. 创建富文本消息
    参考官方文档 发送富文本消息
    • 创建一个content对象
privatestaticJSONObjectcreateOuterContent(String title,String message,String detail,String startTime,String endTime){JSONObject result =newJSONObject(); result.put("post",createPostJsonObject(title, message, detail, startTime, endTime));return result;}privatestaticJSONObjectcreatePostJsonObject(String title,String message,String detail,String startTime,String endTime){JSONObject result =newJSONObject(); result.put("zh_cn",createZhCNJsonObject(title, message, detail, startTime, endTime));return result;}privatestaticJSONObjectcreateZhCNJsonObject(String title,String message,String detail,String startTime,String endTime){JSONObject result =newJSONObject(); result.put("title", title); result.put("content",createContentList(message, detail, startTime, endTime));return result;}privatestaticJSONArraycreateContentList(String message,String detail,String startTime,String endTime){JSONArray result =newJSONArray();JSONArray item1 =newJSONArray(); item1.add(createInnerHeadContent("message")); item1.add(createInnerTextContent(message)); result.add(item1);JSONArray item2 =newJSONArray(); item2.add(createInnerHeadContent("detail")); item2.add(createInnerTextContent(detail)); result.add(item2);JSONArray item3 =newJSONArray(); item3.add(createInnerHeadContent("startTime")); item3.add(createInnerTextContent(startTime)); result.add(item3);JSONArray item4 =newJSONArray(); item4.add(createInnerHeadContent("endTime")); item4.add(createInnerTextContent(endTime)); result.add(item4);return result;}privatestaticJSONObjectcreateInnerHeadContent(String tag){JSONObject result =newJSONObject(); result.put("tag","text"); result.put("text", tag+": ");return result;}privatestaticJSONObjectcreateInnerTextContent(String text){JSONObject result =newJSONObject(); result.put("tag","text"); result.put("text", text);return result;}
  • 再创建完整的json对象

完整代码如下

java版本

publicclassFeishuWebhook{privatestaticfinalLogger logger =LoggerFactory.getLogger(FeishuWebhook.class);publicstaticfinalStringDEFAULT_DATETIME_FORMATTER_STR="yyyy-MM-dd HH:mm:ss";publicstaticfinalDateTimeFormatterDEFAULT_DATETIME_FORMATTER=DateTimeFormatter.ofPattern(DEFAULT_DATETIME_FORMATTER_STR);publicstaticvoidsend(String url,String secret,AlertDO alertDO){ logger.info("FeishuWebhook.send, url:{}, alertDO={}", url, alertDO);JSONObject requestBody =createRequestBody(secret, alertDO); logger.info("requestBody:{}", requestBody);JSONObject result =HttpUtils.postForJsonObject(url,null,null, requestBody); logger.info("result:{}", result);}privatestaticStringgenSign(String secret,long timestamp)throwsNoSuchAlgorithmException,InvalidKeyException{//把timestamp+"\n"+密钥当做签名字符串String stringToSign = timestamp +"\n"+ secret;//使用HmacSHA256算法计算签名Mac mac =Mac.getInstance("HmacSHA256"); mac.init(newSecretKeySpec(stringToSign.getBytes(StandardCharsets.UTF_8),"HmacSHA256"));byte[] signData = mac.doFinal(newbyte[]{});returnnewString(Base64.encodeBase64(signData));}privatestaticJSONObjectcreateRequestBody(String secret,AlertDO alertDO){JSONObject requestBody =newJSONObject();long seconds =LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().getEpochSecond(); logger.info("seconds:{}", seconds);// int seconds = 1734515343;try{String sign =genSign(secret, seconds); requestBody.put("timestamp", seconds); requestBody.put("sign", sign); requestBody.put("msg_type","post");String title ="通知";String message = alertDO.getMessage();String detail = alertDO.getDetail();String startTime =DEFAULT_DATETIME_FORMATTER.format(LocalDateTime.ofInstant(alertDO.getStartTime().toInstant(),ZoneId.systemDefault()));String endTime =DEFAULT_DATETIME_FORMATTER.format(LocalDateTime.ofInstant(alertDO.getEndTime().toInstant(),ZoneId.systemDefault())); requestBody.put("content",createOuterContent(title, message, detail, startTime, endTime));}catch(Exception e){ e.printStackTrace();}return requestBody;}privatestaticJSONObjectcreateOuterContent(String title,String message,String detail,String startTime,String endTime){JSONObject result =newJSONObject(); result.put("post",createPostJsonObject(title, message, detail, startTime, endTime));return result;}privatestaticJSONObjectcreatePostJsonObject(String title,String message,String detail,String startTime,String endTime){JSONObject result =newJSONObject(); result.put("zh_cn",createZhCNJsonObject(title, message, detail, startTime, endTime));return result;}privatestaticJSONObjectcreateZhCNJsonObject(String title,String message,String detail,String startTime,String endTime){JSONObject result =newJSONObject(); result.put("title", title); result.put("content",createContentList(message, detail, startTime, endTime));return result;}privatestaticJSONArraycreateContentList(String message,String detail,String startTime,String endTime){JSONArray result =newJSONArray();JSONArray item1 =newJSONArray(); item1.add(createInnerHeadContent("message")); item1.add(createInnerTextContent(message)); result.add(item1);JSONArray item2 =newJSONArray(); item2.add(createInnerHeadContent("detail")); item2.add(createInnerTextContent(detail)); result.add(item2);JSONArray item3 =newJSONArray(); item3.add(createInnerHeadContent("startTime")); item3.add(createInnerTextContent(startTime)); result.add(item3);JSONArray item4 =newJSONArray(); item4.add(createInnerHeadContent("endTime")); item4.add(createInnerTextContent(endTime)); result.add(item4);return result;}privatestaticJSONObjectcreateInnerHeadContent(String tag){JSONObject result =newJSONObject(); result.put("tag","text"); result.put("text", tag+": ");return result;}privatestaticJSONObjectcreateInnerTextContent(String text){JSONObject result =newJSONObject(); result.put("tag","text"); result.put("text", text);return result;}}

python版本
FeishuBotHypertextWithSecret.py

import base64 import hashlib import hmac from datetime import datetime import requests WEBHOOK_URL ="https://open.feishu.cn/open-apis/bot/v2/hook/xx" WEBHOOK_SECRET ="ssssssss"classLarkBot:def__init__(self, secret:str)->None:ifnot secret:raise ValueError("invalid secret key") self.secret = secret defgen_sign(self, timestamp:int)->str: string_to_sign ='{}\n{}'.format(timestamp, self.secret) hmac_code = hmac.new( string_to_sign.encode("utf-8"), digestmod=hashlib.sha256 ).digest() sign = base64.b64encode(hmac_code).decode('utf-8')return sign defsend(self)->None: timestamp =int(datetime.now().timestamp()) sign = self.gen_sign(timestamp) params ={"timestamp": timestamp,"sign": sign,"msg_type":"post","content":{"post":{"zh_cn":{"title":"项目更新通知","content":[[{"tag":"text","text":"项目有更新: "},{"tag":"a","text":"请查看","href":"http://www.example.com/"},{"tag":"at","user_id":"ou_18eac8********17ad4f02e8bbbb"}]]}}}} resp = requests.post(url=WEBHOOK_URL, json=params) resp.raise_for_status() result = resp.json()if result.get("code")and result["code"]!=0:print(result["msg"])returnprint("消息发送成功")defmain(): bot = LarkBot(secret=WEBHOOK_SECRET) bot.send()if __name__ =='__main__': main()

LarkBotWithoutSecret.py

from datetime import datetime import requests WEBHOOK_URL ="https://open.feishu.cn/open-apis/bot/v2/hook/sss"classLarkBot:defsend(self, content:str)->None: timestamp =int(datetime.now().timestamp()) params ={"timestamp": timestamp,"msg_type":"text","content":{"text": content},} resp = requests.post(url=WEBHOOK_URL, json=params) resp.raise_for_status() result = resp.json()if result.get("code")and result["code"]!=0:print(result["msg"])returnprint("消息发送成功")defmain(): bot = LarkBot() bot.send(content="我是一只高级鸽子!")if __name__ =='__main__': main()

Read more

软件工程的范式演进:深度解构低代码(Low-Code)的技术逻辑与未来图景

软件工程的范式演进:深度解构低代码(Low-Code)的技术逻辑与未来图景

随着企业数字化转型进入深水区,传统交付模式与爆发式业务需求之间的矛盾日益凸显。低代码(Low-Code)作为一种基于高度抽象化的开发范式,正从边缘工具演变为核心生产力。本文将从技术演进史、辩证价值论及全栈化趋势三个维度,深度剖析低代码的本质,并探讨以星图云开发者平台为代表的新一代全场景生产力工具如何重新定义软件工程。 一、溯源与定义:从指令驱动到模型驱动 低代码并非横空出世,其本质是软件工程中“抽象层级”的不断提升。 从早期的机器指令到汇编语言,再到高级程序设计语言(Java, Python等),程序员的操作对象始终在远离底层硬件,向人类逻辑靠近。20世纪80年代,第四代编程语言(4GL)尝试通过声明式语法减少代码量;2014年,Forrester正式定义了“低代码”概念。 现代低代码平台(LCAP)的核心逻辑在于:通过图形化建模(Visual Modeling)替代命令式编码(Imperative Coding)。 它将通用的界面交互、数据存储、业务流程封装为可复用的组件或卡片,开发者通过编排这些逻辑单元,即可实现复杂应用的快速交付。 二、 辩证思考:低代码的“银弹”之

快速掌握URDF机器人Unity导入:2025年终极完整指南

快速掌握URDF机器人Unity导入:2025年终极完整指南 【免费下载链接】URDF-ImporterURDF importer 项目地址: https://gitcode.com/gh_mirrors/ur/URDF-Importer 想要在Unity中快速构建机器人仿真环境?URDF Importer正是您需要的强大工具。这款官方开源插件能够将标准的URDF机器人描述文件无缝导入Unity,自动解析几何结构、运动学参数和物理属性,让机器人开发流程变得前所未有的高效。本文将带您从零开始,全面掌握URDF机器人模型的Unity导入技巧。 🎯 工具核心价值与适用场景 为什么选择URDF Importer? URDF(Unified Robot Description Format)是机器人领域的标准描述格式,而Unity提供了强大的物理引擎和渲染能力。URDF Importer完美桥接了这两个世界,让您能够: * 🔧 标准化导入:完整支持URDF规范,自动提取连杆、关节、惯性参数 * 🎮 物理仿真:基于Unity PhyX 4.0 Articulation Bo

Qwen3-ASR-1.7B多场景落地:博物馆AR导览语音→实时转写→关联文物知识图谱推送

Qwen3-ASR-1.7B多场景落地:博物馆AR导览语音→实时转写→关联文物知识图谱推送 想象一下,你走进一座宏伟的博物馆,面对一件精美的青铜器,心中充满好奇。你戴上AR眼镜,对着它轻声问:“这件文物是什么年代的?有什么故事?”几秒钟后,眼镜屏幕上不仅出现了详细的文字介绍,还推送了与之相关的其他展品、历史背景视频,甚至推荐了展厅里下一件值得看的文物。 这背后,正是语音识别技术从“听懂”到“理解”,再到“智能关联”的完美演绎。今天,我们就来聊聊如何利用Qwen3-ASR-1.7B这款高精度语音识别模型,打造一个从语音导览到知识推送的智能博物馆解决方案。 1. 为什么是Qwen3-ASR-1.7B? 在博物馆这种开放、嘈杂且充满回声的环境里,对语音识别的要求非常苛刻。游客可能来自天南海北,带着各种口音;背景里可能有其他游客的交谈声、孩子的跑动声、甚至展品多媒体播放的声音。传统的语音识别方案在这里常常“水土不服”。 Qwen3-ASR-1.7B就像是专门为这种复杂场景定制的“耳朵”。它有几个硬核优势,让它特别适合博物馆: * 听得准:1.

【论文笔记】Scalable Defense against In-the-wild Jailbreaking Attacks with Safety Context Retrieval

论文信息 论文标题: Scalable Defense against In-the-wild Jailbreaking Attacks with Safety Context Retrieval - ICML 2025 论文作者: Taiye Chen , Zeming Wei , Ang Li , Yisen Wang - PKU 论文链接:http://arxiv.org/abs/2505.15753 关键词: LLM Safety, Jailbreaking, RAG 研究背景 尽管大语言模型(LLMs)经过了人类反馈强化学习(RLHF)等安全对齐技术处理,但仍易受到“越狱攻击”(Jailbreaking Attacks)的威胁,即通过精心设计的提示词诱导模型产生有害输出。