在 Flask 应用程序中将唯一的游戏 ID 绑定到用户以处理对服务器的多个请求
Tying a unique game id to a user in a Flask app to handle multiple requests to the server
我用 Python 构建了一个国际象棋应用程序,并使用 Flask 创建了一个网站供用户下棋。我使用 Heroku 来部署应用程序 (http://pythonchessapp.herokuapp.com/)。我是网络开发的新手,想知道如何处理多个用户(在不同的笔记本电脑或选项卡上)在网站上玩应用程序?比如每个用户都有一个唯一的游戏 ID 来为不同的请求提供不同的游戏。下面是我的一些路线和初始化游戏的代码。我基本上初始化了一个处理移动和跟踪棋盘状态的棋盘对象。我使用 js 将移动信息发送到服务器以进行移动。我还想在用户退出网站后结束游戏。有人有什么想法吗?
我只包括创建板和呈现初始页面的初始路由,以及处理执行动作的路由。
from logic.chess_board import Board
from logic.chess_pieces import *
b = Board()
@app.route('/', methods=["GET", "POST"])
@app.route('/chess', methods=["GET", "POST"])
def chess():
flipped = b.flipped
img_dict = b.board_html()
return render_template('base.html', img_dict=img_dict, flipped=flipped)
@app.route('/execute', methods=['GET', 'POST'])
def execute():
if request.method == "POST":
castle = None
error = False
outcome = False
empty = None
sq_one = eval(request.get_json()['sq_one'])
sq_two = eval(request.get_json()['sq_two'])
piece = b.board[sq_one]
if type(piece) == King and (piece.castle['king_side'] == sq_two or piece.castle['queen_side'] == sq_two):
y = sq_one[1]
if piece.castle['king_side'] == sq_two:
r_one = str((8, y))
r_two = str((6, y))
elif piece.castle['queen_side'] == sq_two:
r_one = str((1, y))
r_two = str((4, y))
castle = [r_one, r_two]
try:
b.move(sq_one, sq_two)
if b.game_over():
outcome = b.outcome
empty = b.js_remove()
except Exception as e:
error = str(e)
response = {'error': error, 'castle': castle, 'empty': empty, 'outcome': outcome}
return make_response(jsonify(response))
如果您不想在服务器上存储任何信息,使用唯一 ID 是解决问题的好方法。每个请求都足以识别谁是谁。
但是,我认为最好的方法是使用 Flask 实现会话。 https://pythonbasics.org/flask-sessions/。这是一种在网络会话期间保留有关每个用户的信息的方法。
这可以通过库 cachelib
以 pickled 格式存储您的 Board
实例,使用 Flask 的 session
对象在 cookie 中存储唯一键来实现。
安装 pip install cachelib
或将 cachelib
添加到您的 requirements.txt
。
首先导入所需的库并初始化缓存:
from flask import Flask, session
import pickle
from uuid import uuid4
from cachelib.simple import SimpleCache
c = SimpleCache(default_timeout=0)
app.config['SECRET_KEY'] = 'somesupersecretkey'
app = Flask(__name__)
return 唯一 ID 的快速函数:
def generate_id():
return uuid4().__str__()
我们不会在全局级别设置 b = Board()
,而是在一个函数内执行此操作,然后 return 它。
所以我们可以定义一个加载板的函数。这将查看 session
对象(cookie 存储)中是否存在键 game_id
。如果是,我们从缓存中加载板。如果没有,这个函数只会创建一个新的板。您还可以在此块的 else
子句中执行其他电路板初始化步骤:
def load_board():
if 'game_id' in session:
pb = c.get(session['game_id'])
board = pickle.loads(pb)
else:
# Initialize new board
board = Board()
return board
现在我们创建一个保存棋盘的函数。这会立即腌制我们作为参数传递的 board
,然后将其保存在缓存中。根据 session
对象(cookie 存储)中是否存在 game_id
,它将使用该 ID 或生成一个新 ID。
def save_board(board):
pb = pickle.dumps(board)
if 'game_id' in session:
c.set(session['game_id'], pb)
else:
unique_id = generate_id()
session['game_id'] = unique_id
c.set(unique_id, pb)
使用这些实用函数,您现在可以跨请求保留一个板:
@app.route('/chess', methods=["GET", "POST"])
def chess():
b = load_board()
flipped = b.flipped
img_dict = b.board_html()
save_board(b)
return render_template('base.html', img_dict=img_dict, flipped=flipped)
那么另一条路线:
@app.route('/execute', methods=['GET', 'POST'])
def execute():
if request.method == "POST":
b = load_board()
# All of your logic
# Finally save the board
save_board(b)
return make_response(jsonify(response))
您可能有不同的方法来设计此功能。SimpleCache
将所有内容存储在内存中,这应该没问题,假设您只有 运行 和 1 个 gunicorn worker。
最终,如果您的工作量超过了单个 worker,或者发现您的 web dyno 的内存占用量过高,您可以轻松地将 SimpleCache
换成 RedisCache
,而无需更改太多逻辑。这也需要在 dyno 重新启动时保留数据。
cachelib
库很小,因此您可以 read the code 查看其他可用的后端和方法。
我用 Python 构建了一个国际象棋应用程序,并使用 Flask 创建了一个网站供用户下棋。我使用 Heroku 来部署应用程序 (http://pythonchessapp.herokuapp.com/)。我是网络开发的新手,想知道如何处理多个用户(在不同的笔记本电脑或选项卡上)在网站上玩应用程序?比如每个用户都有一个唯一的游戏 ID 来为不同的请求提供不同的游戏。下面是我的一些路线和初始化游戏的代码。我基本上初始化了一个处理移动和跟踪棋盘状态的棋盘对象。我使用 js 将移动信息发送到服务器以进行移动。我还想在用户退出网站后结束游戏。有人有什么想法吗?
我只包括创建板和呈现初始页面的初始路由,以及处理执行动作的路由。
from logic.chess_board import Board
from logic.chess_pieces import *
b = Board()
@app.route('/', methods=["GET", "POST"])
@app.route('/chess', methods=["GET", "POST"])
def chess():
flipped = b.flipped
img_dict = b.board_html()
return render_template('base.html', img_dict=img_dict, flipped=flipped)
@app.route('/execute', methods=['GET', 'POST'])
def execute():
if request.method == "POST":
castle = None
error = False
outcome = False
empty = None
sq_one = eval(request.get_json()['sq_one'])
sq_two = eval(request.get_json()['sq_two'])
piece = b.board[sq_one]
if type(piece) == King and (piece.castle['king_side'] == sq_two or piece.castle['queen_side'] == sq_two):
y = sq_one[1]
if piece.castle['king_side'] == sq_two:
r_one = str((8, y))
r_two = str((6, y))
elif piece.castle['queen_side'] == sq_two:
r_one = str((1, y))
r_two = str((4, y))
castle = [r_one, r_two]
try:
b.move(sq_one, sq_two)
if b.game_over():
outcome = b.outcome
empty = b.js_remove()
except Exception as e:
error = str(e)
response = {'error': error, 'castle': castle, 'empty': empty, 'outcome': outcome}
return make_response(jsonify(response))
如果您不想在服务器上存储任何信息,使用唯一 ID 是解决问题的好方法。每个请求都足以识别谁是谁。
但是,我认为最好的方法是使用 Flask 实现会话。 https://pythonbasics.org/flask-sessions/。这是一种在网络会话期间保留有关每个用户的信息的方法。
这可以通过库 cachelib
以 pickled 格式存储您的 Board
实例,使用 Flask 的 session
对象在 cookie 中存储唯一键来实现。
安装 pip install cachelib
或将 cachelib
添加到您的 requirements.txt
。
首先导入所需的库并初始化缓存:
from flask import Flask, session
import pickle
from uuid import uuid4
from cachelib.simple import SimpleCache
c = SimpleCache(default_timeout=0)
app.config['SECRET_KEY'] = 'somesupersecretkey'
app = Flask(__name__)
return 唯一 ID 的快速函数:
def generate_id():
return uuid4().__str__()
我们不会在全局级别设置 b = Board()
,而是在一个函数内执行此操作,然后 return 它。
所以我们可以定义一个加载板的函数。这将查看 session
对象(cookie 存储)中是否存在键 game_id
。如果是,我们从缓存中加载板。如果没有,这个函数只会创建一个新的板。您还可以在此块的 else
子句中执行其他电路板初始化步骤:
def load_board():
if 'game_id' in session:
pb = c.get(session['game_id'])
board = pickle.loads(pb)
else:
# Initialize new board
board = Board()
return board
现在我们创建一个保存棋盘的函数。这会立即腌制我们作为参数传递的 board
,然后将其保存在缓存中。根据 session
对象(cookie 存储)中是否存在 game_id
,它将使用该 ID 或生成一个新 ID。
def save_board(board):
pb = pickle.dumps(board)
if 'game_id' in session:
c.set(session['game_id'], pb)
else:
unique_id = generate_id()
session['game_id'] = unique_id
c.set(unique_id, pb)
使用这些实用函数,您现在可以跨请求保留一个板:
@app.route('/chess', methods=["GET", "POST"])
def chess():
b = load_board()
flipped = b.flipped
img_dict = b.board_html()
save_board(b)
return render_template('base.html', img_dict=img_dict, flipped=flipped)
那么另一条路线:
@app.route('/execute', methods=['GET', 'POST'])
def execute():
if request.method == "POST":
b = load_board()
# All of your logic
# Finally save the board
save_board(b)
return make_response(jsonify(response))
您可能有不同的方法来设计此功能。SimpleCache
将所有内容存储在内存中,这应该没问题,假设您只有 运行 和 1 个 gunicorn worker。
最终,如果您的工作量超过了单个 worker,或者发现您的 web dyno 的内存占用量过高,您可以轻松地将 SimpleCache
换成 RedisCache
,而无需更改太多逻辑。这也需要在 dyno 重新启动时保留数据。
cachelib
库很小,因此您可以 read the code 查看其他可用的后端和方法。