以处理对服务器的多个请求

以处理对服务器的多个请求

本文介绍了在Flask应用中将唯一的游戏ID绑定给用户,以处理对服务器的多个请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用Python构建了一个国际象棋应用程序,并使用Flask创建了一个供用户玩的网站。我使用Heroku部署了该应用程序()。我是Web开发的新手,想知道如何处理网站上运行该应用程序的多个用户(分别在笔记本电脑或标签上)?每个用户都有一个唯一的游戏ID,可以根据不同的请求提供不同的游戏。以下是我的一些路线和初始化游戏代码。我基本上是初始化一个处理移动并跟踪板状态的Board对象。我使用js将移动信息发送到服务器以进行移动。我也想在用户退出网站后结束游戏。没有人有任何想法吗?

I built a chess app with Python and used Flask to create a site for users to play on. I used Heroku to deploy the app (http://pythonchessapp.herokuapp.com/). I am new to web development and was wondering how I can handle multiple users (on separate laptops or tabs) going on the site to play the app? Something like having a unique game id per user to serve a different game to different requests. Below is some of my code for routes and initializing games. I basically initialize a Board object that handles moves and tracks board states. I use js to send info on moves to the server to make moves. I would also like to end a game after a user exits the site. Does anyone have any ideas?

我只包括了创建木板和渲染初始页面的初始路线以及处理执行动作的路线。

I've only included the initial route that creates the board and renders the initial page, and the route that deals with executing moves.

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))


推荐答案

这可以通过库 cachelib 使用Flask的会话 Board 的实例c>对象,以在cookie中存储唯一键。

This could be achieved with the library cachelib to store your instance of Board in pickled format, using Flask's session object to store a unique key in the cookie.

使用 pip安装cachelib 进行安装或添加 cachelib requirements.txt

Install with pip install cachelib or add cachelib to your requirements.txt.

首先导入所需的库并初始化缓存:

Start by importing the required libs and initialising the cache:

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__)

返回唯一ID的快速功能:

A quick function to return a unique ID:

def generate_id():
    return uuid4().__str__()

代替设置 b = Board()在全局级别上,我们将在函数内部执行此操作并将其返回。

Instead of setting b = Board() at the global level, we will do this inside a function and return it.

因此我们可以定义一个函数来加载板。这看起来是要查看 session 对象(cookie存储)中是否存在键 game_id 。如果是这样,我们将从缓存中加载电路板。如果没有,此功能将仅创建一个新板。您还可以在此块的 else 子句中执行其他板子初始化步骤:

So we could define a function which loads a board. This looks to see if the key game_id exists in the session object (cookie storage). If it does, we load the board from our cache. If not, this function will just create a new board. You could also do other board initialization steps in the else clause of this block:

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

现在我们创建一个保存板子的函数。这会立即使我们作为参数传递的腌制,然后将其保存在缓存中。根据 session 对象(cookie存储)中是否存在 game_id ,它将使用该ID或生成一个

Now we create a function which saves the board. This immediately pickles the board we pass as an argument, then saves it in the cache. Depending on whether a game_id exists in the session object (cookie storage) it will either use that ID, or generate a new one.

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)

使用这些实用程序功能,您现在可以在所有请求中保留董事会:

With these utility functions, you can now persist a board across requests:

@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 可以将所有内容存储在内存中,这应该很好,假设您只与一名Gunicorn工人一起跑步。

There's probably different ways you could design this functionality in. SimpleCache stores everything in memory, which should be fine, assuming you only run with 1 gunicorn worker.

最终,如果您超出了一个工人的负担,或者发现您的Web dyno的内存占用量太大,则可以切换 SimpleCache 可以轻松实现 RedisCache ,而无需更改太多逻辑。

Eventually if you outgrew a single worker, or found the memory footprint of your web dyno was too high, you could switch SimpleCache out for RedisCache easily without changing much logic. This would also be needed to persist the data across dyno restarts.

cachelib 库很小,因此您可以以查看其他可用的后端和方法。

The cachelib library is tiny so you can read the code to see the other available backends and methods.

这篇关于在Flask应用中将唯一的游戏ID绑定给用户,以处理对服务器的多个请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-23 05:29