Чтобы получить общее представление о кэшировании сеансов на стороне сервера, вы выполните внедрение небольшого приложения, используя микроплатформу для веб-разработки на языке Python Flask. Поскольку внимание будет уделяться основным понятиям, а не особенностям конкретной платформы и языка, вы можете транслировать примеры на веб-платформу и язык программирования по своему выбору.

Чтобы начать работу с 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, где можно посмотреть, как работает приложение. Заполнитель your_flask_endpoint необходимо заменить публичным именем DNS вашего инстанса EC2, как и в разделе «Требования».

Доступны три маршрута: «/», /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

В поле «Источник» можно начать вводить имя группы безопасности, а затем выбрать ее идентификатор из списка. Дополнительные сведения о группах безопасности можно найти в документации или справочнике по правилам групп безопасности.


Вернемся к примеру. Теперь вы внесете небольшие изменения, которые позволят сохранить данные сеанса в 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 импортировано и инициализировано, а индекс увеличивает показания счетчика и отображает их пользователю.

Обратите внимание, что увеличение показаний счетчика выполняется с помощью команды HINCRBY. Это происходит потому, что хэш Redis используется для сеанса каждого пользователя.


Теперь вы зададите время жизни (TTL) сеанса на стороне сервера. Это всего лишь одна дополнительная строка кода, а фрагмент будет включать только маршрут «/».

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 секунд. Это очень короткое время жизни, используемое только для этого примера. Если запустить приложение сейчас, можно увидеть, как индекс обновляет счетчик посещений. Но если не посещать эту страницу в течение 10 секунд, при следующем обновлении счетчик вернется к значению «1».


Этого короткого примера достаточно для изучения основ сеансов на стороне сервера, но в реальной обстановке вы поступите по-другому: после аутентификации пользователя вы не будете сохранять его имя, а сгенерируете и сохраните токен. Этот токен будет представлять собой ключ Redis, в которым будут храниться все данные сеанса на стороне сервера. Вы также можете отменить некоторые представленные здесь операции, чтобы при каждом доступе к сеансу на стороне сервера время TTL обновлялось без вашего участия. В репозитории вы найдете пример, в котором предоставляется класс SessionStore для отмены такого поведения.