如何使用Let's Encrypt证书创建Python HTTPS Web服务器?

2024-06-23 18:26:03 发布

您现在位置:Python中文网/ 问答频道 /正文

多亏了这个社区的帮助,我已经完成了通过聊天发送HTML5游戏的Python电报机器人! 不幸的是,为了让bot获取分数,我需要在bot中实际设置一个HTTP服务器来获取分数。通过我的研究,我似乎不知道如何使用ssl在python中创建服务器,而不进行自签名(因为当用户点击玩游戏时,它会给出一个空白页面)

我买了一个域名,它已经设置了我的VPS IP地址,虽然我有一个Apache的ssl证书

有人能帮我安排一下吗?由于发送不安全的HTTP连接或自签名连接将导致应用程序中出现空白页

多谢各位

Edit1:Bot代码:

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"));
            }
        }

原始Bot由Mark Powers


Tags: inselfidgamemessageuidifdef
1条回答
网友
1楼 · 发布于 2024-06-23 18:26:03

在对问题和评论作了一些澄清之后,让我试着发表一些评论。这可能远不是一个现成的解决方案,更多的是关于寻找什么的提示

最终目标是从HTML5+JS网页触发setGameScore请求,同时对该网页进行正确的SSL加密。该页面可以独立于bot托管,在这种情况下JS代码应该自己发出请求(下面的方法1),或者通过基于python的web服务器托管在与bot相同的脚本中(下面的方法2+3),在这种情况下,目标是

  1. 让JS代码向该Web服务器发出请求,以便该Web服务器执行请求并
  2. 确保SSL加密,以便网站可以集成到Telegams游戏设置中

方法1:让网站直接做

目前,您的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侦听“localhost”,并让Apache/Nginx将流量转发到正确的端口。这方面的灵感主要来自here。在这种情况下,使用letsencrypt加密apache/nginx应该相当简单

相关问题 更多 >

    热门问题