如何使用 Let's Encrypt 证书创建 Python HTTPS Web 服务器?
How to create a Python HTTPS Webserver using Let's Encrypt certificate?
我已经完成了我的 Python 电报机器人通过聊天发送 HTML5 游戏,感谢这个社区的帮助!
不幸的是,为了让机器人获取分数,我需要在机器人中实际设置一个 HTTP 服务器才能这样做。通过我的研究,我似乎无法弄清楚如何在 python 中使用 ssl 创建一个服务器,而不是自签名(因为当用户点击玩游戏时它会给出一个空白页面).
我买了一个域,它已经设置了我的 VPS IP 地址,尽管我有 Apache 的 ssl 证书...
有人可以帮我设置吗?由于发送和不安全的 HTTP 连接或自签名连接将导致应用程序内出现空白页面...
非常感谢!
Edit1:机器人代码:
import configparser, threading, requests, json, re, time, sys
from uuid import uuid4
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
from telegram import InlineQueryResultGame, ParseMode, InputTextMessageContent
from telegram.ext import Updater, CommandHandler, CallbackQueryHandler, InlineQueryHandler, CommandHandler, CallbackContext
from http.server import HTTPServer, BaseHTTPRequestHandler
def error_callback(update, context):
logger.warning('Update "%s" caused error "%s"', update, context.error)
class Global:
def __init__(self):
return
class GameHTTPRequestHandler(BaseHTTPRequestHandler):
def __init__(self, *args):
BaseHTTPRequestHandler.__init__(self, *args)
def do_GET(self):
if "#" in self.path:
self.path = self.path.split("#")[0]
if "?" in self.path:
(route, params) = self.path.split("?")
else:
route = self.path
params = ""
route = route[1:]
params = params.split("&")
if route in Global.games:
self.send_response(200)
self.end_headers()
self.wfile.write(open(route+'.html', 'rb').read())
elif route == "setScore":
params = {}
for item in self.path.split("?")[1].split("&"):
if "=" in item:
pair = item.split("=")
params[pair[0]] = pair[1]
print(params)
if "imid" in params:
Global.bot.set_game_score(params["uid"], params["score"], inline_message_id=params["imid"])
else:
Global.bot.set_game_score(params["uid"], params["score"], message_id=params["mid"], chat_id=params["cid"])
self.send_response(200)
self.end_headers()
self.wfile.write(b'Set score')
else:
self.send_response(404)
self.end_headers()
self.wfile.write(b'Invalid game!')
def start(update, context):
Global.bot.send_game(update.message.chat_id, Global.featured)
def error(update, context):
print(update, error)
def button(update, context):
print(update)
query = update.callback_query
game = query.game_short_name
uid = str(query.from_user.id)
if query.message:
mid = str(query.message.message_id)
cid = str(query.message.chat.id)
url = "http://" + Global.host + ":"+Global.port + "/" + game + "?uid="+uid+"&mid="+mid+"&cid="+cid
else:
imid = update.callback_query.inline_message_id
url = "http://" + Global.host + ":"+Global.port + "/" + game + "?uid="+uid+"&imid="+imid
print(url)
Global.bot.answer_callback_query(query.id, text=game, url=url)
def inlinequery(update, context):
query = update.inline_query.query
results = []
for game in Global.games:
if query.lower() in game.lower():
results.append(InlineQueryResultGame(id=str(uuid4()),game_short_name=game))
Global.update.inline_query.answer(results)
def main():
config = configparser.ConfigParser()
config.read('config.ini')
token = config['DEFAULT']['API_KEY']
Global.games = config['DEFAULT']['GAMES'].split(',')
Global.host = config['DEFAULT']['HOST']
Global.port = config['DEFAULT']['PORT']
Global.featured = config['DEFAULT']['FEATURED']
updater = Updater(token=token, use_context=True)
dp = updater.dispatcher
dp.add_handler(CommandHandler('start', start))
dp.add_handler(InlineQueryHandler(inlinequery))
dp.add_handler(CallbackQueryHandler(button))
dp.add_error_handler(error)
Global.bot = updater.bot
print("Polling telegram")
updater.start_polling()
print("Starting http server")
http = HTTPServer((Global.host, int(Global.port)), GameHTTPRequestHandler)
http.serve_forever()
if __name__ == '__main__':
main()
HTML5游戏内代码,与分数相关:
function gameOver() {
isGameOver = true;
clearInterval(gameInterval);
const urlParams = new URLSearchParams(window.location.search);
const uid = urlParams.get('uid');
const mid = urlParams.get('mid');
const cid = urlParams.get('cid');
const imid = urlParams.get('imid');
if (imid) {
const request = new Request(`/setScore?uid=${uid}&imid=${imid}&score=${score}`);
fetch(request).then(response => console.log("set score"));
}
else {
const request = new Request(`/setScore?uid=${uid}&mid=${mid}&cid=${cid}&score=${score}`);
fetch(request).then(response => console.log("set score"));
}
}
的原创机器人
在对评论的问题进行了一些澄清之后,让我尝试发表一些评论。这可能远非一个现成的解决方案,更多的是关于寻找什么的提示。
最终目标是从 HTML5 + JS 网页触发 setGameScore
请求,同时对该网页进行适当的 SSL 加密。该页面可以独立于机器人托管,在这种情况下,JS 代码应该自己发出请求(下面的方法 1),或者通过基于 python 的网络服务器在与机器人相同的脚本中托管(方法2 + 3),在这种情况下,目标是
- 让 JS 代码向该网络服务器发出请求,以便网络服务器执行请求并且
- 确保 SSL 加密,以便网站可以集成到 Telegams 游戏设置中。
方法一:让网站直接做
当前您的 JS 代码执行类似
的操作
const request = new Request(`/setScore?uid=${uid}&imid=${imid}&score=${score}`);
fetch(request).then(response => console.log("set score"));
我对 JS 的了解有限,但从 this 等来源来看,似乎
fetch("https://api.telegram.org/botTOKEN/setGameScore?...").then(response => console.log("set score"));
应该已经成功了
方法 2:使用 BaseHTTPRequestHandler
找出 SSL
这似乎是一个更笼统的话题。例如。我发现了这些看起来很相似的问题:
方法 3:使用反向代理来处理 SSL 内容
即让 BaseHTTPRequestHandler
监听“本地主机”并让 Apache/Nginx 将流量转发到正确的端口。这方面的灵感基本上来自于here。在这种情况下,使用 letsencrypt 加密 apache/nginx 应该相当简单。
我已经完成了我的 Python 电报机器人通过聊天发送 HTML5 游戏,感谢这个社区的帮助! 不幸的是,为了让机器人获取分数,我需要在机器人中实际设置一个 HTTP 服务器才能这样做。通过我的研究,我似乎无法弄清楚如何在 python 中使用 ssl 创建一个服务器,而不是自签名(因为当用户点击玩游戏时它会给出一个空白页面).
我买了一个域,它已经设置了我的 VPS IP 地址,尽管我有 Apache 的 ssl 证书...
有人可以帮我设置吗?由于发送和不安全的 HTTP 连接或自签名连接将导致应用程序内出现空白页面...
非常感谢!
Edit1:机器人代码:
import configparser, threading, requests, json, re, time, sys
from uuid import uuid4
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
from telegram import InlineQueryResultGame, ParseMode, InputTextMessageContent
from telegram.ext import Updater, CommandHandler, CallbackQueryHandler, InlineQueryHandler, CommandHandler, CallbackContext
from http.server import HTTPServer, BaseHTTPRequestHandler
def error_callback(update, context):
logger.warning('Update "%s" caused error "%s"', update, context.error)
class Global:
def __init__(self):
return
class GameHTTPRequestHandler(BaseHTTPRequestHandler):
def __init__(self, *args):
BaseHTTPRequestHandler.__init__(self, *args)
def do_GET(self):
if "#" in self.path:
self.path = self.path.split("#")[0]
if "?" in self.path:
(route, params) = self.path.split("?")
else:
route = self.path
params = ""
route = route[1:]
params = params.split("&")
if route in Global.games:
self.send_response(200)
self.end_headers()
self.wfile.write(open(route+'.html', 'rb').read())
elif route == "setScore":
params = {}
for item in self.path.split("?")[1].split("&"):
if "=" in item:
pair = item.split("=")
params[pair[0]] = pair[1]
print(params)
if "imid" in params:
Global.bot.set_game_score(params["uid"], params["score"], inline_message_id=params["imid"])
else:
Global.bot.set_game_score(params["uid"], params["score"], message_id=params["mid"], chat_id=params["cid"])
self.send_response(200)
self.end_headers()
self.wfile.write(b'Set score')
else:
self.send_response(404)
self.end_headers()
self.wfile.write(b'Invalid game!')
def start(update, context):
Global.bot.send_game(update.message.chat_id, Global.featured)
def error(update, context):
print(update, error)
def button(update, context):
print(update)
query = update.callback_query
game = query.game_short_name
uid = str(query.from_user.id)
if query.message:
mid = str(query.message.message_id)
cid = str(query.message.chat.id)
url = "http://" + Global.host + ":"+Global.port + "/" + game + "?uid="+uid+"&mid="+mid+"&cid="+cid
else:
imid = update.callback_query.inline_message_id
url = "http://" + Global.host + ":"+Global.port + "/" + game + "?uid="+uid+"&imid="+imid
print(url)
Global.bot.answer_callback_query(query.id, text=game, url=url)
def inlinequery(update, context):
query = update.inline_query.query
results = []
for game in Global.games:
if query.lower() in game.lower():
results.append(InlineQueryResultGame(id=str(uuid4()),game_short_name=game))
Global.update.inline_query.answer(results)
def main():
config = configparser.ConfigParser()
config.read('config.ini')
token = config['DEFAULT']['API_KEY']
Global.games = config['DEFAULT']['GAMES'].split(',')
Global.host = config['DEFAULT']['HOST']
Global.port = config['DEFAULT']['PORT']
Global.featured = config['DEFAULT']['FEATURED']
updater = Updater(token=token, use_context=True)
dp = updater.dispatcher
dp.add_handler(CommandHandler('start', start))
dp.add_handler(InlineQueryHandler(inlinequery))
dp.add_handler(CallbackQueryHandler(button))
dp.add_error_handler(error)
Global.bot = updater.bot
print("Polling telegram")
updater.start_polling()
print("Starting http server")
http = HTTPServer((Global.host, int(Global.port)), GameHTTPRequestHandler)
http.serve_forever()
if __name__ == '__main__':
main()
HTML5游戏内代码,与分数相关:
function gameOver() {
isGameOver = true;
clearInterval(gameInterval);
const urlParams = new URLSearchParams(window.location.search);
const uid = urlParams.get('uid');
const mid = urlParams.get('mid');
const cid = urlParams.get('cid');
const imid = urlParams.get('imid');
if (imid) {
const request = new Request(`/setScore?uid=${uid}&imid=${imid}&score=${score}`);
fetch(request).then(response => console.log("set score"));
}
else {
const request = new Request(`/setScore?uid=${uid}&mid=${mid}&cid=${cid}&score=${score}`);
fetch(request).then(response => console.log("set score"));
}
}
的原创机器人
在对评论的问题进行了一些澄清之后,让我尝试发表一些评论。这可能远非一个现成的解决方案,更多的是关于寻找什么的提示。
最终目标是从 HTML5 + JS 网页触发 setGameScore
请求,同时对该网页进行适当的 SSL 加密。该页面可以独立于机器人托管,在这种情况下,JS 代码应该自己发出请求(下面的方法 1),或者通过基于 python 的网络服务器在与机器人相同的脚本中托管(方法2 + 3),在这种情况下,目标是
- 让 JS 代码向该网络服务器发出请求,以便网络服务器执行请求并且
- 确保 SSL 加密,以便网站可以集成到 Telegams 游戏设置中。
方法一:让网站直接做
当前您的 JS 代码执行类似
的操作const request = new Request(`/setScore?uid=${uid}&imid=${imid}&score=${score}`);
fetch(request).then(response => console.log("set score"));
我对 JS 的了解有限,但从 this 等来源来看,似乎
fetch("https://api.telegram.org/botTOKEN/setGameScore?...").then(response => console.log("set score"));
应该已经成功了
方法 2:使用 BaseHTTPRequestHandler
找出 SSL
这似乎是一个更笼统的话题。例如。我发现了这些看起来很相似的问题:
方法 3:使用反向代理来处理 SSL 内容
即让 BaseHTTPRequestHandler
监听“本地主机”并让 Apache/Nginx 将流量转发到正确的端口。这方面的灵感基本上来自于here。在这种情况下,使用 letsencrypt 加密 apache/nginx 应该相当简单。