// lark_bot_server.py
#!/usr/bin/env python
# --coding:utf-8--
from http.server import BaseHTTPRequestHandler, HTTPServer
from os import path
import json
from urllib import request, parse
APP_ID = "abcdefg"
APP_SECRET = "hijklmn"
APP_VERIFICATION_TOKEN = "opqrst"
class RequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write(b"Hello tqz!")
def do_POST(self):
# 解析请求 body
req_body = self.rfile.read(int(self.headers['content-length']))
obj = json.loads(req_body.decode("utf-8"))
# 校验 verification token 是否匹配,token 不匹配说明该回调并非来自开发平台
token = obj.get("token", "")
if token != APP_VERIFICATION_TOKEN:
print("verification token not match, token =", token)
self.response("")
return
# 根据 type 处理不同类型事件
type = obj.get("type", "")
if "url_verification" == type: # 验证请求 URL 是否有效
self.handle_request_url_verify(obj)
elif "event_callback" == type: # 事件回调
# 获取事件内容和类型,并进行相应处理,此处只关注给机器人推送的消息事件
event = obj.get("event")
if event.get("type", "") == "message":
self.handle_message(event)
return
return
def handle_request_url_verify(self, post_obj):
# 原样返回 challenge 字段内容
challenge = post_obj.get("challenge", "")
rsp = {'challenge': challenge}
self.response(json.dumps(rsp))
return
def handle_message(self, event):
# 此处只处理 text 类型消息,其他类型消息忽略
msg_type = event.get("msg_type", "")
if msg_type != "text":
print("unknown msg_type =", msg_type)
self.response("")
return
# 调用发消息 API 之前,先要获取 API 调用凭证:tenant_access_token
access_token = self.get_tenant_access_token()
if access_token == "":
self.response("")
return
# 机器人 echo 收到的消息
self.send_message(access_token, event.get("open_id"), event.get("text"))
self.response("")
return
def response(self, body):
self.send_response(200)
self.send_header('Content-Type', 'application/json')
self.end_headers()
self.wfile.write(body.encode())
def get_tenant_access_token(self):
url = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal/"
headers = {
"Content-Type" : "application/json"
}
req_body = {
"app_id": APP_ID,
"app_secret": APP_SECRET
}
data = bytes(json.dumps(req_body), encoding='utf8')
req = request.Request(url=url, data=data, headers=headers, method='POST')
try:
response = request.urlopen(req)
except Exception as e:
print(e.read().decode())
return ""
rsp_body = response.read().decode('utf-8')
rsp_dict = json.loads(rsp_body)
code = rsp_dict.get("code", -1)
if code != 0:
print("get tenant_access_token error, code =", code)
return ""
return rsp_dict.get("tenant_access_token", "")
def send_message(self, token, open_id, text):
url = "https://open.feishu.cn/open-apis/message/v4/send/"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer " + token
}
req_body = {
"open_id": open_id,
"msg_type": "text",
"content": {
"text": text
}
}
data = bytes(json.dumps(req_body), encoding='utf8')
req = request.Request(url=url, data=data, headers=headers, method='POST')
try:
response = request.urlopen(req)
except Exception as e:
print(e.read().decode())
return
rsp_body = response.read().decode('utf-8')
rsp_dict = json.loads(rsp_body)
code = rsp_dict.get("code", -1)
if code != 0:
print("send message error, code = ", code, ", msg =", rsp_dict.get("msg", ""))
def run():
port = 3500
server_address = ('', port)
httpd = HTTPServer(server_address, RequestHandler)
print("start.....")
httpd.serve_forever()
if __name__ == '__main__':
run()
// lark_bot_cli.py
import json
import http.client
if __name__ == '__main__':
# 要发送的数据
data = {
'type': 'url_verification',
'challenge': 'tqz_for_test',
'token': '...'
}
# 本地服务器的 IP 地址和端口号
server_address = ('localhost', 3500)
# 发送 POST 请求到 /path,注意这里的路径需要匹配到 RequestHandler 中的 URL 路由规则
conn = http.client.HTTPConnection(*server_address)
conn.request('POST', '/path', body=json.dumps(data), headers={'Content-type': 'application/json'})
response = conn.getresponse()
if response.status == 200:
# 请求成功,处理返回的数据
response_data = response.read()
print("response_data: " + str(response_data))
else:
# 请求失败
print('Error:', response.status, response.reason)
conn.close()