{"id":9920,"date":"2025-02-13T16:20:48","date_gmt":"2025-02-13T08:20:48","guid":{"rendered":"https:\/\/sdeno.com\/?p=9920"},"modified":"2025-02-13T16:23:03","modified_gmt":"2025-02-13T08:23:03","slug":"webhook%e6%b6%88%e6%81%af%e6%8e%a8%e9%80%81%e6%9c%8d%e5%8a%a1%e5%99%a8%e7%ae%80%e5%8d%95%e6%90%ad%e5%bb%ba","status":"publish","type":"post","link":"https:\/\/sdeno.com\/?p=9920","title":{"rendered":"webhook\u6d88\u606f\u63a8\u9001\u670d\u52a1\u5668\u7b80\u5355\u642d\u5efa"},"content":{"rendered":"<p>\u57fa\u4e8enode.js\u642d\u5efa\uff0c\u540e\u7aef\u7528\u4efb\u610f\u8bed\u8a00\u90fd\u884c<\/p>\n<p><span style=\"color: #ff0000;\">\u670d\u52a1\u5668\uff1a<\/span><\/p>\n<p>\u5b89\u88c5\u4f9d\u8d56\uff1a<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">npm init -y\r\nnpm install express body-parser dotenv<\/pre>\n<p>&nbsp;<\/p>\n<p>\u540e\u7aef\u4ee3\u7801\uff1a<\/p>\n<p>server.js<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">const express = require('express');\r\nconst bodyParser = require('body-parser');\r\nconst fs = require('fs').promises;\r\nconst path = require('path');\r\nrequire('dotenv').config();\r\n\r\nconst app = express();\r\nconst port = process.env.PORT || 3000;\r\n\r\n\/\/ \u65e5\u5fd7\u5b58\u50a8\u914d\u7f6e\r\nconst LOG_DIR = 'logs';\r\nconst LOG_FILE = path.join(LOG_DIR, 'webhook_logs.json');\r\n\r\n\/\/ \u521d\u59cb\u5316\u65e5\u5fd7\u76ee\u5f55\r\nasync function initLogDir() {\r\n  try {\r\n    await fs.access(LOG_DIR);\r\n  } catch {\r\n    await fs.mkdir(LOG_DIR);\r\n    await fs.writeFile(LOG_FILE, '[]');\r\n  }\r\n}\r\n\r\n\/\/ \u4fdd\u5b58\u65e5\u5fd7\r\nasync function saveLog(data) {\r\n  try {\r\n    const logs = await readLogs();\r\n    logs.unshift({\r\n      id: Date.now(),\r\n      timestamp: new Date().toISOString(),\r\n      ...data\r\n    });\r\n    await fs.writeFile(LOG_FILE, JSON.stringify(logs.slice(0, 100), null, 2));\r\n  } catch (error) {\r\n    console.error('\u4fdd\u5b58\u65e5\u5fd7\u5931\u8d25:', error);\r\n  }\r\n}\r\n\r\n\/\/ \u8bfb\u53d6\u65e5\u5fd7\r\nasync function readLogs() {\r\n  try {\r\n    const data = await fs.readFile(LOG_FILE, 'utf8');\r\n    return JSON.parse(data);\r\n  } catch {\r\n    return [];\r\n  }\r\n}\r\n\r\napp.use(bodyParser.json());\r\napp.use(bodyParser.urlencoded({ extended: true }));\r\n\r\n\/\/ \u8bb0\u5f55\u6240\u6709\u8bf7\u6c42\r\napp.use((req, res, next) =&gt; {\r\n  console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);\r\n  next();\r\n});\r\n\r\n\/\/ Webhook\u63a5\u6536\u7aef\u70b9\r\napp.post('\/webhook', async (req, res) =&gt; {\r\n  try {\r\n    const webhookData = {\r\n      headers: req.headers,\r\n      body: req.body,\r\n      query: req.query,\r\n      receivedAt: new Date().toISOString()\r\n    };\r\n\r\n    \/\/ \u4fdd\u5b58\u63a5\u6536\u5230\u7684\u6570\u636e\r\n    await saveLog(webhookData);\r\n\r\n    console.log('\u6536\u5230Webhook\u8bf7\u6c42:', {\r\n      time: webhookData.receivedAt,\r\n      body: webhookData.body\r\n    });\r\n\r\n    res.status(200).json({\r\n      status: 'success',\r\n      message: 'Webhook received successfully'\r\n    });\r\n  } catch (error) {\r\n    console.error('\u5904\u7406Webhook\u5931\u8d25:', error);\r\n    res.status(500).json({\r\n      status: 'error',\r\n      message: error.message\r\n    });\r\n  }\r\n});\r\n\r\n\/\/ \u67e5\u770b\u65e5\u5fd7\u7684API\u7aef\u70b9\r\napp.get('\/logs', async (req, res) =&gt; {\r\n  try {\r\n    const page = parseInt(req.query.page) || 1;\r\n    const limit = parseInt(req.query.limit) || 10;\r\n    const logs = await readLogs();\r\n    \r\n    const startIndex = (page - 1) * limit;\r\n    const endIndex = page * limit;\r\n    \r\n    res.json({\r\n      data: logs.slice(startIndex, endIndex),\r\n      total: logs.length,\r\n      page,\r\n      limit\r\n    });\r\n  } catch (error) {\r\n    res.status(500).json({\r\n      status: 'error',\r\n      message: error.message\r\n    });\r\n  }\r\n});\r\n\r\n\/\/ \u67e5\u770b\u5355\u6761\u65e5\u5fd7\u8be6\u60c5\r\napp.get('\/logs\/:id', async (req, res) =&gt; {\r\n  try {\r\n    const logs = await readLogs();\r\n    const log = logs.find(l =&gt; l.id === parseInt(req.params.id));\r\n    \r\n    if (!log) {\r\n      return res.status(404).json({\r\n        status: 'error',\r\n        message: 'Log not found'\r\n      });\r\n    }\r\n    \r\n    res.json(log);\r\n  } catch (error) {\r\n    res.status(500).json({\r\n      status: 'error',\r\n      message: error.message\r\n    });\r\n  }\r\n});\r\n\r\n\/\/ \u5065\u5eb7\u68c0\u67e5\u7aef\u70b9\r\napp.get('\/health', (req, res) =&gt; {\r\n  res.status(200).json({\r\n    status: 'healthy',\r\n    time: new Date().toISOString()\r\n  });\r\n});\r\n\r\n\/\/ \u542f\u52a8\u670d\u52a1\u5668\r\nasync function startServer() {\r\n  await initLogDir();\r\n  app.listen(port, () =&gt; {\r\n    console.log(`Webhook\u670d\u52a1\u5668\u5df2\u542f\u52a8: http:\/\/localhost:${port}`);\r\n  });\r\n}\r\n\r\nstartServer();<\/pre>\n<p>&nbsp;<\/p>\n<p>\u4f7f\u7528curl\u53d1\u9001\u6d4b\u8bd5\u8bf7\u6c42\uff1a<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">curl -X POST http:\/\/localhost:3000\/webhook \\\r\n  -H \"Content-Type: application\/json\" \\\r\n  -d '{\"message\": \"\u6d4b\u8bd5\u6d88\u606f\", \"type\": \"test\"}'<\/pre>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #ff0000;\">\u5ba2\u6237\u7aef\uff1a<\/span><\/p>\n<p>\u67e5\u770b\u53d1\u6765\u7684\u6570\u636e<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">curl \"http:\/\/localhost:3000\/logs?page=1&amp;limit=10\"<\/pre>\n<p>&nbsp;<\/p>\n<p>\u914d\u5408\u624b\u673a\u7aefapp\u4f7f\u7528\uff0c\u53ef\u4ee5\u628a\u63a5\u6536\u6765\u7684\u77ed\u4fe1\u81ea\u52a8\u53d1\u9001\u5230\u5730\u5740\u4e0a\u67e5\u770b<\/p>\n<blockquote class=\"wp-embedded-content\" data-secret=\"ex8jHefj6V\"><p><a href=\"https:\/\/sdeno.com\/?p=9901\">\u77ed\u4fe1\u8f6c\u53d1\u5230\u6307\u5b9a\u90ae\u7bb1<\/a><\/p><\/blockquote>\n<p><iframe loading=\"lazy\" class=\"wp-embedded-content\" sandbox=\"allow-scripts\" security=\"restricted\" style=\"position: absolute; visibility: hidden;\" title=\"\u300a\u77ed\u4fe1\u8f6c\u53d1\u5230\u6307\u5b9a\u90ae\u7bb1\u300b\u2014\u968f\u8eab\u7b14\u8bb0\" src=\"https:\/\/sdeno.com\/?p=9901&#038;embed=true#?secret=1kWxk1dKGL#?secret=ex8jHefj6V\" data-secret=\"ex8jHefj6V\" width=\"500\" height=\"282\" frameborder=\"0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\"><\/iframe><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u57fa\u4e8enode.js\u642d\u5efa\uff0c\u540e\u7aef\u7528\u4efb\u610f\u8bed\u8a00\u90fd\u884c \u670d\u52a1\u5668\uff1a \u5b89\u88c5\u4f9d\u8d56\uff1a npm init -y npm instal [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-9920","post","type-post","status-publish","format-standard","hentry","category-wordpress"],"_links":{"self":[{"href":"https:\/\/sdeno.com\/index.php?rest_route=\/wp\/v2\/posts\/9920","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sdeno.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sdeno.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sdeno.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sdeno.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=9920"}],"version-history":[{"count":2,"href":"https:\/\/sdeno.com\/index.php?rest_route=\/wp\/v2\/posts\/9920\/revisions"}],"predecessor-version":[{"id":9922,"href":"https:\/\/sdeno.com\/index.php?rest_route=\/wp\/v2\/posts\/9920\/revisions\/9922"}],"wp:attachment":[{"href":"https:\/\/sdeno.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=9920"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sdeno.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=9920"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sdeno.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=9920"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}