🎯 学习目标:学会调用外部 API、Webhook、数据同步
⏱️ 阅读时间:约 12 分钟
💡 前置要求:无
🔌 API 集成能做什么?
核心能力总览
| HTTP 请求 | ||
| Webhook | ||
| 数据同步 | ||
| 认证管理 |
🌐 HTTP 请求
基础使用
module.exports = {name: 'http-request',asyncexecute({ method, url, headers, body }) {try {const response = awaitfetch(url, { method,headers: {'Content-Type': 'application/json', ...headers },body: body ? JSON.stringify(body) : undefined });if (!response.ok) {thrownewError(`HTTP ${response.status}: ${response.statusText}`); }const data = await response.json();return data; } catch (error) {console.error('HTTP 请求失败:', error);throw error; } }};调用第三方 API
场景 1:天气 API
module.exports = {name: 'weather-api',asyncexecute({ city }) {try {const response = awaitfetch(`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${process.env.WEATHER_API_KEY}&units=metric&lang=zh_cn` );const data = await response.json();return`🌤️ ${data.name} 天气🌡️ 温度:${data.main.temp}°C💧 湿度:${data.main.humidity}%💨 风速:${data.wind.speed} m/s🌤️ 状况:${data.weather[0].description} `.trim(); } catch (error) {console.error('天气查询失败:', error);throw error; } }};场景 2:GitHub API
module.exports = {name: 'github-api',asyncexecute({ action, repo, params }) {constBASE_CONFIG = {baseUrl: 'https://api.github.com',headers: {'Authorization': `token ${process.env.GITHUB_TOKEN}`,'Accept': 'application/vnd.github.v3+json' },maxDisplayItems: 10 };if (!action) thrownewError('缺少必要参数:action');if (!repo) thrownewError('缺少必要参数:repo');try {constfetchGitHubData = async (endpoint) => {const response = awaitfetch(`${BASE_CONFIG.baseUrl}${endpoint}`, {headers: BASE_CONFIG.headers });if (!response.ok) {const errorData = await response.json().catch(() => ({ message: '未知错误' }));thrownewError(`GitHub API 请求失败 [${response.status}]:${errorData.message}`); }return response.json(); };const actionConfig = {issues: {endpoint: `/repos/${repo}/issues`,titlePrefix: '📋',itemFormatter: (issue) =>`#${issue.number}${issue.title} (${issue.state})` },pr: {endpoint: `/repos/${repo}/pulls`,titlePrefix: '🔀',itemFormatter: (pr) =>`#${pr.number}${pr.title} by ${pr.user?.login || '未知用户'}` } };const config = actionConfig[action];const dataList = awaitfetchGitHubData(config.endpoint);const displayItems = dataList.slice(0, BASE_CONFIG.maxDisplayItems);const itemsText = displayItems.length > 0 ? displayItems.map(config.itemFormatter).join('\n') : '暂无相关数据';return`${config.titlePrefix}${repo}${action === 'issues' ? 'Issues' : 'Pull Requests'}${itemsText} `.trim(); } catch (error) {console.error(`GitHub API 调用失败 [action: ${action}, repo: ${repo}]:`, error.message);thrownewError(`获取 ${action} 失败:${error.message}`); } }};🔔 Webhook
接收 GitHub Webhook
module.exports = {name: 'github-webhook',asyncinit() {try {awaitregisterWebhook('/webhook/github', async (request) => {const valid = awaitverifySignature( request.headers['x-hub-signature-256'], request.body, process.env.GITHUB_WEBHOOK_SECRET );if (!valid) {return { status: 401, body: 'Invalid signature' }; }const event = request.headers['x-github-event'];const payload = request.body;if (event === 'push') {awaithandlePush(payload); }if (event === 'pull_request') {awaithandlePullRequest(payload); }return { status: 200, body: 'OK' }; });return'✅ GitHub Webhook 已注册'; } catch (error) {console.error('注册 Webhook 失败:', error);throw error; } }};🔄 数据同步
定时同步
module.exports = {name: 'data-sync',asyncinit() {try {// 每小时同步一次awaitcreateCronJob({cron: '0 * * * *',task: async () => {console.log('开始数据同步...');// 同步 CRM 客户数据const customers = awaitsyncCRM();// 同步 ERP 订单数据const orders = awaitsyncERP();// 生成同步报告const report = `📊 **数据同步报告**✅ CRM 客户:${customers.count} 条✅ ERP 订单:${orders.count} 条同步时间:${newDate().toLocaleString()} `.trim();awaitsendToFeishu({chatId: getDataChannelId(),content: report }); } });return'✅ 数据同步已启用,每小时执行一次'; } catch (error) {console.error('数据同步初始化失败:', error);throw error; } }};🔐 认证管理
API Key 管理
classSecretManager {constructor() {this.storage = process.env.SECRET_STORAGE || 'env'; }asyncget(secretName) {if (this.storage === 'env') {return process.env[secretName]; }if (this.storage === 'aws-secrets') {returnawaitthis.getFromAWSSecrets(secretName); }if (this.storage === 'vault') {returnawaitthis.getFromVault(secretName); }thrownewError(`未知的密钥存储方式:${this.storage}`); }}// 使用示例const secrets = newSecretManager();const apiKey = await secrets.get('OPENAI_API_KEY');自动刷新 Token
module.exports = {name: 'token-refresh',asyncinit() {try {// 每天检查 Token 是否过期awaitcreateCronJob({cron: '0 0 * * *',task: async () => {const tokens = awaitlistTokens();for (const token of tokens) {if (isExpiringSoon(token)) {const newToken = awaitrefreshToken(token);awaitupdateToken(token.service, newToken);console.log(`已刷新 ${token.service} Token`); } } } });return'✅ Token 自动刷新已启用'; } catch (error) {console.error('Token 刷新初始化失败:', error);throw error; } }};💡 实用场景
场景 1:跨平台消息同步
module.exports = {name: 'message-bridge',asyncinit() {try {// 飞书 → 钉钉awaitsubscribeEvent('feishu.message', async (event) => {const message = event.message;awaitsendToDingtalk({webhook: process.env.DINGTALK_WEBHOOK,content: `📢 飞书消息\n\n${message.content.text}` }); });// 钉钉 → 飞书awaitsubscribeEvent('dingtalk.message', async (event) => {const message = event.message;awaitsendToFeishu({chatId: process.env.FEISHU_CHAT_ID,content: `📢 钉钉消息\n\n${message.text}` }); });return'✅ 消息桥接已启用'; } catch (error) {console.error('消息桥接初始化失败:', error);throw error; } }};场景 2:CI/CD 通知
module.exports = {name: 'cicd-notify',asyncinit() {try {awaitregisterWebhook('/webhook/cicd', async (request) => {const { pipeline, status, commit } = request.body;let emoji, color;if (status === 'success') { emoji = '✅'; color = 'green'; } elseif (status === 'failed') { emoji = '❌'; color = 'red'; } else { emoji = '⏳'; color = 'yellow'; }awaitsendToFeishu({chatId: getDevChatId(),content: `${emoji} **CI/CD 通知**流水线:${pipeline}状态:${status}提交:${commit.message}分支:${commit.branch} `.trim() });return { status: 200 }; });return'✅ CI/CD 通知已启用'; } catch (error) {console.error('CI/CD 通知初始化失败:', error);throw error; } }};✅ 学完这篇你能做什么
学完 Day 20,你将能够:
✅ 调用外部 API(天气、GitHub、钉钉、企业微信) ✅ 配置 Webhook(GitHub、支付通知) ✅ 实现数据同步(定时同步、双向同步) ✅ 管理 API 密钥(SecretManager、自动刷新 Token) ✅ 处理 API 相关错误
🔜 下篇预告
Day 21:第三周复盘:企业级应用总结
📚 第三周内容回顾 ❓ 常见问题 Q&A 📊 学习成果自测
💬 互动环节
你想集成什么外部系统?留言分享!
公众号:OpenClaw 研习社系列:OpenClaw 30 天入门到精通作者:OpenClaw 研习社
夜雨聆风