我该如何从python客户端监听Webhook(https地址端点)?

时间:2019-09-25 18:45:45

标签: python node.js

我有一个nodejs端点,该作业将通过POST HTTP调用由作业调用,该POST包含JSON格式的作业数据的详细信息?如何从python客户端监听webhook(https地址)以获取工作数据?

https://company/api/bats_push

app.post("/api/bats_push",(req, res) => {
        //console.log("Calling bats_push...")
        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');
        });
});

python客户端:

data = {'name': 'joe', 'age': 20}
webhook_url = 'http://localhost:3000/api/bats_push'
json_data = json.dumps(data)
print json_data
try:
    r = requests.post(webhook_url,data=json_data.encode("utf8"),verify=False,headers={"Content-Type": "application/json"},timeout=10.0)
    print "posted"
    print(r.status_code, r.reason)
    print r.url
except Exception as e:
    print (e)

错误:-

HTTPConnectionPool(host='localhost', port=3000): Read timed out. (read timeout=10.0)

5 个答案:

答案 0 :(得分:2)

通常,“ 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

另一方面,如果节点进程当前正在https://company/api/bats_hook/处接收 POST请求,而您想在作业进入时通知python进程,那就是另一个问题。您可以通过axios.post或类似的方法将信息发送到单独的python服务器上(这可能是最简单的选择),也可以将数据存储在python进程可以访问它的位置。 Redis是一个不错的选择,因为您可以轻松地设置发布/订阅系统,并且节点和python进程可以在同一台计算机上,也可以在不同的计算机上。如果它们在同一台计算机上,则还可以将数据转储到日志文件中,然后将其读入python。将数据从一个进程发送到另一个进程称为inter-process communication,并且变得很快。

如果要对node_redisredis-py使用redis,则实现可能类似于:

// 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部分将仅用于本地调试,则与需要部署时会做出不同的选择。

答案 1 :(得分:1)

至少对我来说,您描述的设置看起来有些奇怪。

要澄清(主要是为我自己):

  • 您确实有一个node.js服务器,该服务器使用HTTP上的POST服务/api/bats_hook端点。
  • 有正在运行的 jobs 会立即访问并获取信息。
  • 您要求一种使用Python获得该响应(=作业数据)的方法。

仅当 job 是将POST请求发送到您的node.js服务器并在HTTP 200上接收JSON的Python部分时,条件才能成立。否则,您将尝试窃听从node.js服务器获取外部请求及其相应的响应,而无需成为实际的通信伙伴。

如果 job 代码是Python,并且您想正确地发布node.js服务,请使用requests Python软件包。发送请求并获取JSON响应是两行代码。

如果 job 代码不在您的控制之下,或者您不希望Python“ hook”处于活动状态的位置,则可能是闻到了糟糕的体系结构或滥用了一种不希望使用的设置。请澄清。

答案 2 :(得分:0)

如果您尝试收听webhooks(http),则可以通过在python中创建一个http服务器来实现。 https://www.acmesystems.it/python_http

但是,如果您要查找网络套接字,则应使用@Thom建议的以ws://开头的网址。

答案 3 :(得分:0)

您保存发布的数据并将其返回给感兴趣的消费者。这意味着您创建了一个网络挂钩网桥

示例节点脚本:

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请求按“原样”保存。标头,查询和正文的内容未处理。提取后,客户端应相应地解析数据。

答案 4 :(得分:0)

在我的职业生涯中使用与付款相关的系统;通常,webhooks是您为启动的进程而获得的回调,但它与主流分开,因此不会无故保留内存。

按照你说的去做

[Webhook] => Python => Node.js

,我无法理解调用该过程的确切原因,该过程在整个周期中都增加了Webhook流。无论如何,都不应更改答案。

因此,基本上,您需要一个API端点,该端点将从此第三方Webhook调用。您决定如何使用python促进这一点完全是您的要求。使用诸如Django,性能等框架的API系统运行起来并不会那么复杂。与之相关的问题是我不愿赘述的。

让我知道您是否清楚。