3 回答
TA贡献1862条经验 获得超6个赞
通常,“webhook”是在线服务的一项功能,它在您部署了 HTTP 服务器的公共 URL 上向您的应用发送请求,以响应服务中的某些事件。需要在发送请求的任何内容中配置 url,它没有在接收代码中明确设置。
监听 webhook 的是一个定义了合适端点的 HTTP 服务器。要创建服务器,您可以使用许多不同的包,但像Flask这样简单的东西是一个不错的起点。
最小的视图代码看起来像:
@app.route('/api/bats_hook')
def bats_hook():
data = request.get_json()
print(data)
return 'OK'
如果发送 POST(您的 nodejs 服务?)的任何东西都需要能够向您的服务器发送请求,那么您要么需要部署服务器以使其可公开访问,要么将服务设置为将请求发送到您的公共 IP . 如果它在同一台机器上,您可以使用私有 IP,或者localhost.
另一方面,如果一个节点进程当前正在接收POST 请求https://company/api/bats_hook/,并且您想在有作业时通知 python 进程,这是一个不同的问题。您可以通过或类似方式将该信息发送到单独的 python 服务器axios.post(这可能是最简单的选择),或者将数据存储在 python 进程可以访问它的位置。Redis将是一个不错的选择,因为您可以轻松设置发布/订阅系统,并且 node 和 python 进程可以在同一台机器上,也可以在不同的机器上。如果它们在同一台机器上,您也可以将数据转储到日志文件并将其读入 python。从一个进程向另一个进程发送数据称为进程间通信,并且它很快变得复杂。
如果您要使用 redis,使用node_redis和redis-py,则实现可能如下所示:
// javascript
var redis = require("redis"),
redisClient = redis.createClient();
app.post("/api/bats_hook", (req, res, next) => {
console.log(req.query.params)
console.log(req.body)
console.log(req.body.name)
// This publishes a message to the "bats hook channel"
redisClient.publish("bats hook channel", JSON.stringify({
params: req.query.params,
body: req.body,
}));
res.status(200).json({
message: "BATS object",
posts: req.body
});
});
# python
import redis
r = redis.Redis()
p = r.pubsub()
p.subscribe('bats hook channel')
# This blocks and reads any messages from the "bats hook channel" as they come in
for message in p.listen():
print(message)
很大程度上取决于您的预期用途。如果 python 部分仅用于本地调试,您将做出与需要部署不同的选择。
TA贡献1836条经验 获得超4个赞
你描述的设置看起来有点奇怪,至少对我来说是这样。
澄清(主要是为了我自己):
您确实有一个使用 HTTP 上的 POST
node.js
服务端点的服务器。/api/bats_hook
有一些作业正在运行,该访问不时指向获取信息。
您要求一种使用 Python 获得该响应(=作业数据)的方法。
仅当作业是向您的服务器发送 POST 请求并在 HTTP 200 上接收 JSON 的 Python 部分时,条件才能成立node.js
。否则,您将尝试窃听以从node.js
服务器获取外部请求及其相应的响应,而不是实际的通讯伙伴。
如果作业代码是 Python,并且您想正确发布node.js
服务,请使用requests
Python 包。发送请求并获取 JSON 响应是两行代码。
如果作业代码不受您的控制,或者不是您希望 Python“钩子”处于活动状态的位置,那么要么闻起来像糟糕的架构,要么以非预期的方式滥用设置。请说清楚。
TA贡献1783条经验 获得超4个赞
您保存发布的数据并将其返回给感兴趣的消费者。这意味着您创建了一个webhook 桥接器。
示例节点脚本:
const http = require('http');
const URL = require('url');
const DATA = [];
const routes = {
'/api/bats_push': (req, res) => {
const d = {
method: req.method,
headers: req.headers,
query: req.query,
body: ''
}
req.on('data', (c) => {
d.body = d.body + c
});
req.on('end', () => {
DATA.push(d);
res.end('Saved');
});
},
'/api/bats_pull': (req, res) => {
const json = JSON.stringify(DATA, true);
DATA.length = 0;
res.statusCode = 200;
res.setHeader('content-type','application/json');
res.end(json);
}
};
const server = http.createServer((req, res) => {
const reqUrl = URL.parse(req.url);
const route = routes[reqUrl.pathname];
if (route) {
req.query = reqUrl.query;
route(req, res);
} else {
res.statusCode = 404;
res.end('Not found');
}
})
server.listen(8080,() => console.info('Server started'));
并且,一个 python 客户端脚本来测试它:
import http.client
import json
print('\nPosting data...')
conn1 = http.client.HTTPConnection('localhost', 8080)
headers1 = {'content-type': 'application/json'}
body1 = {'name': 'joe', 'age': 20}
conn1.request('POST', '/api/bats_push?q=100', json.dumps(body1), headers1)
resp1 = conn1.getresponse()
print(resp1.status,resp1.reason, resp1.read())
conn1.close()
print('\nRetrieving data...')
conn2 = http.client.HTTPConnection('localhost', 8080)
headers2 = {'accept': '*'}
conn2.request('POST', '/api/bats_pull', None, headers1)
resp2 = conn2.getresponse()
resp2Json = json.loads(resp2.read())
print(resp2.status,resp2.reason, resp2Json)
输出:
Posting data...
200 OK b'Saved'
Retrieving data...
200 OK [{'method': 'POST', 'headers': {'host': 'localhost:8080', 'accept-encoding': 'identity', 'content-length': '26', 'content-type': 'application/json'}, 'query': 'q=100', 'body': '{"name": "joe", "age": 20}'}]
此外,HTTP 请求按“原样”保存。不处理标题、查询和正文的内容。客户端应在拉取后相应地解析数据。
添加回答
举报