Ответ сервера и перехват запросов во Flask Python

Flask – функциональный фреймворк, который, несмотря на свою компактность, предоставляет много возможностей. В том числе, и работа с серверами: передача запросов и получение ответов. Фреймворк дает возможность создавать ответ сервера тремя способами, а осуществлять перехват запросов с использованием специальных декораторов. Сегодня поговорим более подробно о том, как осуществлять взаимодействие сервера и клиента с помощью Flask в среде Python.

Ответ сервера

Flask дает возможность реализовать ответ сервера такими способами:

  1. С помощью строки или с использованием шаблонизатора.
  2. Создание специального объекта, отвечающего за ответ. 
  3. Использование кортежа в формате (response, status, headers) или (response, headers).

Следует каждый способ рассмотреть более подробно.

Создание ответа в виде строки

Реализуется с помощью следующего синтаксиса. 

@app.route('/books/<genre>')

def books(genre):

    return "All Books in {} category".format(genre)

Этот способ – довольно распространенный для того, чтобы осуществлять отправку ответа клиенту. Строка автоматически конвертируется в объект ответа, когда Flask понимает, что из функции представления поступает строка. Для этого используется метод make_response(), в котором указывается строка с телом ответа, код HTTP 200 и content-type text/html

Как правило, этого достаточно. Но в некоторых случаях перед тем, как отправлять ответ клиенту, необходимо указывать специальные заголовки. Для этого используется функция make_response().

Использование make_response() для создания ответа 

make_response() – это функция, имеющая такой синтаксис.




res_obj = make_response(res_body, status_code=200)

res_body – этот аргумент являет собой тело ответа, а status_code – дополнительный, его не обязательно использовать. Если так, то передается ответ с кодом 200. 

А такой код демонстрирует процедуру добавления дополнительных заголовков с использованием функции make_response()

from flask import Flask, make_response,




@app.route('/books/<genre>')

def books(genre):

    res = make_response("All Books in {} category".format(genre))

    res.headers['Content-Type'] = 'text/plain'

    res.headers['Server'] = 'Foobar'

    return res

А этот код показывает, как правильно возвращать ошибку 404 с использованием этой функции. 

@app.route('/')

def http_404_handler():

    return make_response("<h2>404 Error</h2>", 400)

Также веб-приложения могут настраивать куки. Этот процесс становится максимально простым благодаря функции make_response(). Приведем пример кода, который добавляет два куки в браузере, выступающем роль клиента. 

@app.route('/set-cookie')

def set_cookie():

    res = make_response("Cookie setter")

    res.set_cookie("favorite-color", "skyblue")

    res.set_cookie("favorite-font", "sans-serif")

    return res

Срок действия этих куков будет вплоть до окончания сессии в браузере. Разработчик может указать собственную дату экспирации (то есть, окончания срока действия), передав в качестве третьего аргумента метода set_cookie() количество секунд.  

@app.route('/set-cookie')

def set_cookie():

    res = make_response("Cookie setter")

    res.set_cookie("favorite-color", "skyblue", 60*60*24*15)

    res.set_cookie("favorite-font", "sans-serif", 60*60*24*15)

    return res

Этот фрагмент кода задает срок хранения куки в течение 15 дней.

Использование кортежей для создания ответов

И последний способ создания ответов – использование неизменяемых последовательностей значений (кортежей). Они должны соответствовать определенному формату. 

(response, status, headers)




(response, headers)




(response, status)

response – это строка, которая служит телом ответа. А код состояния HTTP записывается в элементе кортежа status

Значения заголовков содержатся в headers

@app.route('/')

def http_500_handler():

    return ("<h2>500 Error</h2>", 500)

Если эта функция будет запущена, клиент получит ошибку HTTP 500 Internal Server Error.

Так, как можно не указывать скобки при создании кортежей, то этот код можно представить и в таком виде. 

@app.route('/')

def http_500_handler():

    return "<h2>500 Error</h2>", 500

А с помощью этого кода мы понимаем, как использовать кортежи для указания заголовков. 

@app.route('/')

def render_markdown():

    return "## Heading", 200, {'Content-Type': 'text/markdown'}

Задача: попробуйте определить, что будет делать данная функция. 

@app.route('/transfer')

def transfer():

    return "", 302, {'location': 'https://localhost:5000/login'}

С помощью функции представления пользователь перенаправляется на http://localhost:5000/login с использованием ответа 302. Поскольку перенаправление пользователей происходит довольно часто, во Flask есть специальная функция, отвечающая за это – redirect()

from flask import Flask, redirect




@app.route('/transfer')

def transfer():

    return redirect("https://localhost:5000/login")

По предустановленным параметрам, функция redirect() выполняет 302 редиректы. Если же необходимо 301, то соответствующий код нужно указать во втором аргументе этой функции.

Перехват запросов

Веб-приложения нередко требуют выполнения определенного кода до или после запроса. Например, ставится задача вывести весь перечень IP-адресов пользователей, использующих программу или выполнить авторизацию пользователя, а потом показать ему скрытые страницы. 

Flask предлагает такие декораторы, чтобы избавить от необходимости копировать постоянно один и тот же код в рамках каждой функции представления:

  • before_first_request. С помощью этого декоратора, еще до того, как будет обработан первый запрос, выполняется функция.
  • before_request. Выполнение функции происходит до обработки запроса.
  • after_request. Сначала обрабатывается запрос, а потом выполняется функция. Она не будет вызываться при возникновении исключений в обработчике запросов. Функцией должен быть принят объект ответа, а потом возвращен тот же или новый ответ. 
  • teardown_request. Этот декоратор похож на предыдущий за исключением того, что выполнение функции будет осуществляться вне зависимости от того, возникает ошибка или нет.

Важно учесть, что при возврате ответа функции в before_request обработчик запросов не вызывается.

А теперь следует привести пример кода, который показывает особенности использования этих точек перехвата во Flask. Для начала создадим файл с названием hooks.py, в котором есть такой код. 

from flask import Flask, request, g




app = Flask(__name__)




@app.before_first_request

def before_first_request():

    print("before_first_request() called")




@app.before_request

def before_request():

    print("before_request() called")




@app.after_request

def after_request(response):

    print("after_request() called")

    return response




@app.route("/")

def index():

    print("index() called")

    return '<p>Testings Request Hooks</p>'




if __name__ == "__main__":

    app.run(debug=True)

Затем надо осуществить запуск сервера, а потом создать первый запрос путем перехода на страницу http://localhost:5000/. В консоли, где запускается сервер, должен появиться такой ответ. 

before_first_request() called

before_request() called

index() called

after_request() called

Записи о запросах, чтобы добиться большей краткости, были опущены.

После того, как пользователь перезагрузит страницу, он увидит следующее. 

before_request() called

index() called

after_request() called

Так, как это – второй запрос, то функция before_first_request() вызвана не будет. 

Использование функции abort() для отмены запросов

Flask предусматривает возможность воспользоваться функцией abort(), чтобы отменить запрос с определенным кодом. Могут выдаваться ошибки 404, 500 и другие. Этот пример кода демонстрирует работу этой функции. 

from  flask import  Flask,  abort




@app.route('/')

def index():

    abort(404)

    # код после выполнения abort() не выполняется

После того, как выполнить эту функцию представления, будет возвращена стандартная страница с ошибкой 404.

abort() для других типов ошибок покажет похожие страницы. 

Если стоит задача изменить внешний вид страниц с ошибками, используется декоратор errorhandler.

Как изменять страницы ошибок

Возможно создание и пользовательской страницы с ошибками. Для этого используется декоратор errorhandler. В качестве аргумента он принимает ошибку, для которой создается специальная страница. 

Давайте откроем файл hooks.py, чтобы создать произвольные страницы ошибок. 

from flask import Flask, request, g, abort

#...

#...

@app.after_request

def after_request(response):

    print("after_request() called")

    return response




@app.errorhandler(404)

def http_404_handler(error):

    return "<p>HTTP 404 Error Encountered</p>", 404




@app.errorhandler(500)

def http_500_handler(error):

    return "<p>HTTP 500 Error Encountered</p>", 500




@app.route("/")

def index():

    # print("index() called")

    # return '<p>Testings Request Hooks</p>'

    abort(404)




if  __name__  ==  "__main__":

#...

Следует отметить то, что все обработчики в качестве аргумента принимают аргумент error, в котором содержатся дополнительные сведения о типе ошибки.

Выводы

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

Как видим, Python – универсальный язык, который может быть использован для создания любых программ для любых платформ.

ОфисГуру
Adblock
detector