为了了解服务器端会话缓存背后的基本理念,您将使用 Flask 实施一个小应用程序,Flask 是使用 Python 中进行 Web 开发的微框架。由于将重点放在给定框架和语言的概念上而不是细节上,因此您可以将示例转换为您选择的 Web 框架和编程语言。

如果要开始使用 Flask,请按照安装说明快速入门指南进行操作。

以下是一个最基本的用于登录和注销的应用程序:

syntax: python

import os
from flask import Flask, session, redirect, escape, request

app = Flask(__name__)
app.secret_key = os.environ.get('SECRET_KEY', default=None)

@app.route('/')

def index():

    if 'username' in session:
        return 'Logged in as %s' % escape(session['username'])

    return 'You are not logged in'

@app.route('/login', methods=['GET', 'POST'])

def login():

    if request.method == 'POST':

        session['username'] = request.form['username']
        return redirect('/')

    return '''
        <form method="post">
        <p><input type=text name=username>
        <p><input type=submit value=Login>
        </form>
    '''

@app.route('/logout')

def logout():

    session.pop('username', None)
    return redirect('/')

其余示例将基于这个代码段。可以在此存储库中找到所有示例的代码。

如果您已安装 Flask 并想要启动该应用程序,请将代码复制到名为 example-1.py 的文件中。然后,您需要导出两个环境变量:FLASK_APP 应该设置为 example-1.py,而 SECRET_KEY 应该设置为随机字符串,例如 Y0PJWblKsg1axM4fGW。如果您需要设置环境变量方面的帮助,请查看 Flask 的快速入门指南

完成所有设置后,运行以下命令:

syntax: shell

$ flask run -h 0.0.0.0 -p 5000 --reload

然后转到 http://your_flask_endpoint:5000,在这里,您会看到您的应用程序正在运行。您需要按照要求进行操作,用 EC2 实例的公有 DNS 名称替换 your_flask_endpoint。

有三种路由可供选择:“/”、“/login”和“/logout”。依次访问它们,熟悉其基本行为。

完成模块所需时间:60-90 分钟


示例使用 Cookie 存储用户名。首次访问应用程序时,会话对象中并没有存储用户名。转到“/login”并提供一个用户名后,值存储在签名的 Cookie 中,而您将重定向至主页。然后,如果您转到“/logout”,则用户名将从会话中删除,而您将回到最初的位置。

您将通过服务器端会话扩展此基本应用程序,不过请先确保您可以连接到 Redis。



步骤 2.1

(单击可放大)

步骤 2.1

在示例中,每次提及 Redis 终端节点时,都应使用主终端节点的主机名。 

步骤 2.2

(单击可放大)

步骤 2.2

syntax: shell

$ export REDIS_URL="redis://your_redis_endpoint:6379"

syntax: shell

$ python

syntax: python

>>> import redis
>>> client = redis.Redis.from_url('redis://your_redis_endpoint:6379')
>>> client.ping()

**True**

如果挂起,说明您被“安全组”设置阻止。验证 EC2 实例是否可以访问分配给 ElastiCache 实例的安全组。例如,假设您的 EC2 实例已分配给默认安全组。现在,您可以修改 Amazon ElastiCache 实例的安全组,并添加一个自定义 TCP 规则,以允许来自默认安全组中任何实例的端口 6379 上的连接: 

步骤 2.5

在“源”中,可以开始键入安全组的名称,并能够单击“安全组 ID”。如需了解有关安全组的更多信息,可以查看文档安全组规则引用


我们再回到示例中来。现在,您将了解一些小的更改,这些更改可帮助您将会话数据存储在 Redis 中。以下是实施了这些更改的另一个示例:

syntax: python

import os
import redis
from flask import Flask, session, redirect, escape, request

app = Flask(__name__)

app.secret_key = os.environ.get('SECRET_KEY', default=None)

# BEGIN NEW CODE - PART 1 #
REDIS_URL = os.environ.get('REDIS_URL')
store = redis.Redis.from_url(REDIS_URL)
# END NEW CODE - PART 1 #

@app.route('/')

def index():

    if 'username' in session:

        # BEGIN NEW CODE - PART 2 #
        username = escape(session['username'])
        visits = store.hincrby(username, 'visits', 1)

    return '''
        Logged in as {0}.<br>
        Visits: {1}
        '''.format(username, visits)
        # END NEW CODE - PART 2 #

    return 'You are not logged in'

@app.route('/login', methods=['GET', 'POST'])

def login():

    if request.method == 'POST':
        session['username'] = request.form['username']
        return redirect('/')

    return '''
        <form method="post">
        <p><input type=text name=username>
        <p><input type=submit value=Login>
        </form>'''

@app.route('/logout')

def logout():

    session.pop('username', None)
    return redirect('/')

现在,已导入 Redis 并初始化,索引负责增加一个计数器并向用户显示。

请注意,用于增加计数器的 Redis 命令是 HINCRBY。这是因为您正在为每个用户的会话使用 Redis 哈希。


现在,您要为服务器端会话设置生存时间 (TTL)。它只是多了一行代码,这个代码段将只包含 / route。

syntax: python

...
@app.route('/')

def index():

    if 'username' in session:

        username = escape(session['username'])
        visits = store.hincrby(username, 'visits', 1)
        # BEGIN NEW CODE #
        store.expire(username, 10)
        # END NEW CODE #

        return '''
            Logged in as {0}.<br>
            Visits: {1}
            '''.format(username, visits)

    return 'You are not logged in'
...

存储会话的键将在 10 秒后过期。这是一个非常短的 TTL,仅在此示例中有用。如果立即运行应用程序,您将看到访问索引如何更新“访问”计数器,但是如果您不访问该页面,而是等待 10 秒钟,则下次刷新时,计数器将返回 1。


这个简短的示例足够您了解服务器端会话的基础知识,但是在现实情况中,您的操作会有所不同:对用户进行身份验证后,您将生成并存储令牌,而不是存储用户名。该令牌将代表 Redis 键,所有服务器端会话数据都将存储在该键下。您可能还想抽象化此处介绍的某些行为,以便对服务器端会话的任何访问都可以刷新 TTL,而无需干预。在存储库中,有一个示例提供了一个抽象化该行为的 SessionStore 类。