Эта статья основана на"Веб-разработка Flask на практике》первыйГлава 2 «Flask и HTTP» сокращена и переписана, полный каталог главПожалуйста, посетите главную страницу книгиhttp://helloflask.com/bookПроверить.
HTTP (Hypertext Transfer Protocol, протокол передачи гипертекста) определяет формат и способ передачи информации при обмене между сервером и клиентом и является основой обмена данными во всемирной паутине. В этой статье мы будем использовать процесс цикла запрос-ответ, определенный протоколом HTTP, в качестве основы для понимания различных способов, которыми Flask обрабатывает запросы и ответы.
Примеры программ в этой главе находятся врепозиторий helloflaskВ каталоге demos/http вы можете запустить программу, выполнив следующие действия:
$ git clone https://github.com/greyli/helloflask
$ cd helloflask
$ pipenv install
$ pipenv shell
$ cd demos/http
$ flask run
цикл ответа на запрос
Чтобы приблизиться к реальности, возьмем в качестве примера реальный URL:
http://helloflask.com/hello
Когда мы вводим этот URL-адрес в адресную строку браузера и нажимаем Enter, через некоторое время браузер отображает страницу приветствия. Что за этим стоит? Как вы, наверное, догадались, за ним также стоит программа, подобная той, которую мы написали в главе 1. Он отвечает за получение запроса пользователя и возврат соответствующего контента клиенту для отображения в браузере пользователя. Фактически, каждое веб-приложение включает в себя этот режим обработки, «цикл запроса-ответа»: клиент делает запрос, сервер обрабатывает запрос и возвращает ответ, как показано на следующем рисунке:
Примечания Сторона клиента относится ко всем видам программного обеспечения, предоставляемого пользователям для связи с сервером. В этой книге под клиентом обычно понимается веб-браузер (далее — браузер), такой как Chrome, Firefox, IE и т. д.; под серверной частью (Server Side) понимается сервер, предоставляющий услуги пользователям, и также там, где работают наши программы.
Это основной рабочий режим каждой веб-программы, если пойти дальше, то этот режим содержит больше рабочих единиц.
На следующем рисунке показан фактический поток программы Flask:
Как видно из рисунка выше, HTTP играет решающую роль во всем процессе, это мост между клиентом и сервером.
Когда пользователь получает доступ к URL-адресу, браузер генерирует соответствующий HTTP-запрос и отправляет его на соответствующий веб-сервер через Интернет. Веб-сервер получает запрос и использует WSGI для преобразования данных запроса в формате HTTP в данные Python, которые может использовать наша программа Flask. В программе Flask выполняет соответствующую функцию просмотра в соответствии с запрошенным URL-адресом, получает возвращаемое значение и генерирует ответ. Ответ, в свою очередь, преобразуется WSGI для создания ответа HTTP, который передается через веб-сервер и, наконец, принимается запрашивающим клиентом. Браузер отображает код HTML и CSS, содержащийся в ответе, выполняет код JavaScript и, наконец, отображает проанализированную страницу в окне браузера пользователя.
HTTP-запрос
URL-адрес является источником запроса. Независимо от того, работает ли сервер в Лос-Анджелесе, США, или на нашем собственном компьютере, когда мы вводим URL-адрес, указывающий на адрес, где расположен сервер, на сервер отправляется HTTP-запрос. Стандартный URL-адрес состоит из многих частей, в качестве примера возьмем следующий URL-адрес:
http://helloflask.com/hello?name=Grey
Различные компоненты этого URL показаны в следующей таблице:
Информация |
иллюстрировать |
http:// |
строка протокола, указывающая протокол для использования |
helloflask.com |
Адрес сервера (доменное имя) |
/hello?name=Grey |
Путь к ресурсу для получения (путь), структура каталогов файлов в стиле Unix. |
сообщение запроса
Когда мы посещаем этот URL-адрес в браузере, делается запрос на сервер, где находится http://helloflask.com. Суть запроса заключается в отправке на сервер неких данных.Данные, которые браузер взаимодействует с сервером, называются сообщением, а данные, отправляемые браузером в момент запроса, называются сообщением запроса.Данные, возвращаемые сервер называется ответным сообщением.
Сообщение запроса состоит из запрошенного метода, URL-адреса, версии протокола, полей заголовка и объектов содержимого. Сообщение запроса, сгенерированное предыдущим запросом, показано в следующей таблице:
Описание состава |
Запрос содержимого сообщения |
Заголовок сообщения: строка запроса (метод, URL, протокол) |
GET /hello HTTP/1.1 |
Заголовок сообщения: различные поля заголовка |
Host: helloflask.com Connection: keep-alive Cache-Control: max-age=0 User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36 ... |
пустая строка |
|
тело сообщения |
name=Grey |
Если вы хотите увидеть настоящее HTTP-сообщение, вы можете сделать запрос на любой допустимый URL-адрес в своем браузере, а затем вы сможете увидеть все запросы на загрузку ресурсов, соответствующие URL-адресу, на вкладке «Сеть» инструментов разработчика браузера (F12). Список, щелкните любую запись запроса, чтобы просмотреть информацию о сообщении. На следующем рисунке показан пример использования Chrome для доступа к локальному образцу программы:
Сообщение состоит из заголовка сообщения и тела сообщения, которые разделены пустыми строками.Тело сообщения запроса обычно пусто. Если URL-адрес содержит строку запроса или форма отправлена, текст сообщения будет состоять из строки запроса и данных формы.
HTTP различает разные типы запросов по методу. Например, когда вы посещаете страницу напрямую, метод запроса — GET; когда вы заполняете форму на странице и отправляете ее, метод запроса обычно — POST. В следующей таблице показано несколько распространенных типов методов HTTP:
метод |
иллюстрировать |
GET |
Доступ к ресурсам |
POST |
передача данных |
PUT |
передавать файлы |
DELETE |
удалить ресурс |
HEAD |
Получить заголовок сообщения |
OPTIONS |
Способы попросить поддержки |
Заголовок сообщения содержит различную информацию и настройки запроса, такие как тип клиента, необходимость установки кеша, языковые предпочтения и т. д.
Если запустить программу-пример, то при посещении http://127.0.0.1:5000/hello в браузере сервер разработки выведет в командную строку лог с основной информацией о запросе:
127.0.0.1 - - [02/Aug/2017 09:51:37] "GET /hello HTTP/1.1" 200 –
Объект запроса
Теперь пришло время включить объект запроса Flask request.Этот объект запроса инкапсулирует сообщение запроса, отправленное от клиента, и мы можем получить от него все данные в сообщении запроса.
Как и в предыдущем разделе, начнем с URL. Предполагая, что запрошенный URL-адрес http://helloflask.com/hello?name=Grey, когда Flask получит запрос, объект запроса предоставит несколько атрибутов для получения каждой части URL-адреса. Обычно используемые атрибуты показаны в следующей таблице. :
Атрибуты |
ценность |
path |
u'/hello' |
full_path |
u'/hello?name=Grey' |
host |
u'helloflask.com' |
host_url |
u'http://helloflask.com/ ' |
base_url |
u'http://helloflask.com/hello ' |
url |
u'http://helloflask.com/hello?name=Grey ' |
url_root |
u'http://helloflask.com/ ' |
Помимо URL-адреса, другую информацию в сообщении запроса можно получить с помощью свойств и методов, предоставляемых объектом запроса.Часто используемые части показаны в следующей таблице:
свойство/метод |
иллюстрировать |
args |
Объект Werkzeug ImmutableMultiDict. Сохраните проанализированную строку запроса и получите значение ключа через словарь. Если вы хотите получить неразобранную собственную строку запроса, вы можете использовать свойство query_string |
blueprint |
Название текущего чертежа, концепция чертежей будет подробно представлена во второй части этой книги. |
cookies |
Словарь, содержащий все файлы cookie, отправленные с запросом. |
data |
Содержит данные запроса в виде строки |
endpoint |
значение конечной точки, соответствующее текущему запросу |
files |
Объект Werkzeug MultiDict, содержащий все загруженные файлы, можно получить в виде словаря. Используемый ключ — это значение атрибута name во входном теге файла, а соответствующее значение — объект FileStorage Werkzeug.Вы можете вызвать метод save() и передать путь сохранения для сохранения файла. |
form |
Объект Werkzeug ImmutableMultiDict. Аналогично файлам, содержащим разобранные данные формы. Значение поля формы получается по значению атрибута имени входного тега в качестве ключа |
values |
Объект CombinedMultiDict от Werkzeug, объединяющий значения аргументов и свойств формы |
get_data(cache=True, as_text=False, parse_from_data=False) |
Получите данные в запросе, прочитанные как байтовая строка по умолчанию, установите для as_text значение True, а возвращаемое значение будет декодированной строкой Unicode. |
get_json(self, force=False, silent=False, cache=True) |
Проанализируйте и верните данные в виде JSON. Если тип MIME не JSON, верните None (если только принудительно не установлено значение True); если произойдет ошибка синтаксического анализа, будет выдано исключение BadRequest, предоставленное Werkzeug (если режим отладки не включен , будет возвращен ответ об ошибке 400, который будет подробно описан позже. ), возвращает None, если для параметра молчание установлено значение True; cache устанавливает, следует ли кэшировать проанализированные данные JSON |
headers |
Объект Werkzeug EnvironmentHeaders, содержащий поля заголовков, которыми можно манипулировать в виде словаря. |
is_json |
Определите, являются ли данные JSON по типу MIME, и верните логическое значение. |
json |
Содержит проанализированные данные JSON, вызывает get_json() внутри и получает значение ключа через словарь. |
method |
Запрошенный HTTP-метод |
referrer |
Исходный URL-адрес, по которому был отправлен запрос, то есть реферер |
scheme |
Запрошенный шаблон URL (http или https) |
user_agent |
Пользовательский агент (User Agent, UA), включая тип клиента пользователя, тип операционной системы и другую информацию |
Та же функциональность реализована в нашей тестовой программе. Когда вы посещаете http://localhost:5000/hello?name=Grey, страница загружается и отображает «Привет, Грей!». Это означает, что функция представления, которая обрабатывает этот URL-адрес, получает значение имени параметра запроса из строки запроса следующим образом:
from flask import Flask, request
app = Flask(__name__)
@app.route('/hello')
def hello():
name = request.args.get('name', 'Flask') # 获取查询参数name的值
return '<h1>Hello, %s!</h1>' % name # 插入到返回值中
Следует отметить, что, в отличие от обычного типа словаря, когда мы напрямую используем ключ в качестве индекса для получения данных из свойств (таких как файлы, форма, аргументы) типа MutliDict или ImmutableMultiDict в объекте запроса (например, request. args['name ']), если соответствующий ключ отсутствует, он вернет ответ об ошибке HTTP 400 (неверный запрос, указывающий, что запрос недействителен) вместо создания исключения KeyError, как показано на следующем рисунке. Чтобы избежать этой ошибки, мы должны использовать метод get() для получения данных и вернуть None, если нет соответствующего значения; второй параметр метода get() может установить значение по умолчанию, например, requset.args .get('имя', 'Человек').
Совет. Если включен режим отладки, будет выдано исключение BadRequestKeyError и вместо обычного ответа 400 будет отображаться соответствующая информация о стеке ошибок.
Обработка запросов в Flask
URL-адрес — это адрес, указывающий на ресурс в Интернете. Во Flask нам нужно, чтобы запрошенный URL-адрес соответствовал соответствующей функции просмотра, а возвращаемое значение функции просмотра — это ресурс, соответствующий URL-адресу.
сопоставление маршрутов
Чтобы упростить распределение запросов к соответствующим функциям представления, в экземпляре программы хранится таблица маршрутизации (app.url_map), которая определяет отношение сопоставления между правилами URL и функциями представления. Когда запрос отправлен, Flask попытается сопоставить все правила URL-адресов в этой таблице в соответствии с URL-адресом (частью пути) в сообщении запроса и вызовет функцию просмотра, которая успешно соответствует. Если совпадающее правило URL-адреса не найдено, это означает, что в программе нет функции просмотра, которая обрабатывает этот URL-адрес, и Flask автоматически вернет ответ об ошибке 404 (не найдено, что означает, что ресурс не найден). Вы можете попробовать получить доступ к http://localhost:5000/nothing в своем браузере, потому что в нашей программе нет функции просмотра для обработки этого URL-адреса, поэтому вы получите ответ 404, как показано ниже:
Если вы много путешествуете по Интернету, вам знаком этот код ошибки, указывающий на то, что запрошенный ресурс не найден. Подобно ответу об ошибке 400, упомянутому ранее, этот тип кода ошибки называется кодом состояния HTTP и используется для указания статуса ответа, который подробно обсуждается ниже.
Когда запрошенный URL-адрес успешно соответствует правилу URL-адреса функции представления, будет вызвана соответствующая функция представления. Используйте команду flask route для просмотра всех маршрутов, определенных в программе.Этот список анализируется app.url_map:
$ flask routes
Endpoint Methods Rule
-------- ------- -----------------------
hello GET /hello
go_back GET /goback/<int:age>
hi GET /hi
...
static GET /static/<path:filename>
В выходном тексте мы видим конечную точку (Конечная точка), метод HTTP (Методы) и правило URL (Правило), соответствующие каждому маршруту. Статическая конечная точка — это специальный маршрут, добавленный Flask для доступа к статическим файлам. В частности, мы узнаем в главе 3.
Установите метод прослушивания HTTP
Как видно из списка маршрутов, напечатанного командой flask route в предыдущем разделе, в дополнение к правилам URL каждый маршрут также устанавливает метод прослушивания HTTP. GET является наиболее часто используемым HTTP-методом, поэтому тип метода мониторинга функции представления по умолчанию — GET.Запросы методов HEAD и OPTIONS обрабатываются Flask, а такие методы, как DELETE и PUT, как правило, не реализованы в программе. Позже мы построим Интернет. Эти методы используются только при использовании API.
Мы можем использовать параметр method в декораторе app.route(), чтобы передать итерацию прослушивающих HTTP-методов. Например, следующая функция просмотра прослушивает запросы GET и POST:
@app.route('/hello', methods=['GET', 'POST'])
def hello():
return '<h1>Hello, Flask!</h1>'
Если запрошенный метод не соответствует требованиям, запрос не будет обработан в обычном режиме. Например, метод POST обычно используется при отправке формы, и если функция просмотра, соответствующая отправленному целевому URL-адресу, разрешает только метод GET, тогда Flask автоматически вернет ответ об ошибке 405 (метод не разрешен, что указывает на то, что метод запроса не допускается), как показано ниже:
Определив список методов, мы можем определить несколько функций представления для одного и того же правила URL для обработки запросов с разными методами HTTP соответственно.Мы будем использовать эту функцию при создании веб-API во второй части этой книги.3. Обработка URL
Как видно из приведенного выше списка маршрутов, помимо /hello, эта программа содержит множество правил URL, например /goback/
преобразователь |
иллюстрировать |
string |
Строка без косой черты (по умолчанию) |
int |
Целое число |
float |
число с плавающей запятой |
path |
Строка, содержащая косые черты. Переменная имени файла в правиле URL статического маршрута использует этот преобразователь. |
any |
соответствует элементу в последовательности заданных значений |
uuid |
строка UUID |
Преобразователи задаются особым правилом, а именно «».
@app.route('goback/<int:year>')
def go_back(year):
return '<p>Welcome to %d!</p>' % (2018 - year)
Поведение по умолчанию преобразует не только типы переменных, но и сопоставление URL-адресов. В этом примере, если конвертер не используется, переменная года по умолчанию будет преобразована в строку.Чтобы иметь возможность вычислить количество дней в Python, нам нужно использовать функцию int() для преобразования переменной года в целое число. Однако, если пользователь вводит английские буквы, произойдет ошибка преобразования и будет выдано исключение ValueError, и нам также необходимо выполнить проверку вручную; после использования преобразователя, если переменная, переданная в URL-адресе, не является числом, возникает ошибка 404. ответ будет возвращен напрямую. Например, вы можете попробовать посетить http://localhost:5000/goback/tang.
Единственная особая вещь в использовании - это любой конвертер, вам нужно добавить круглые скобки после конвертера, чтобы указать необязательные значения, то есть «», например:
@app.route('/colors/<any(blue, white, red):color>')
def three_colors(color):
return '<p>Love is patient and kind. Love is not jealous or boastful or proud or rude.</p>'
Когда вы посещаете http://localhost:5000/colors/
Если вы хотите передать предопределенный список в любой конвертер, вы можете создать строку правила URL, отформатировав строку (используя % или функцию format()), например:
colors = ['blue', 'white', 'red']
@app.route('/colors/<any(%s):color>' % str(colors)[1:-1])
...
HTTP-ответ
В программе Flask запрос, отправленный клиентом, запускает соответствующую функцию просмотра, и полученное возвращаемое значение будет использоваться в качестве тела ответа, и, наконец, будет сгенерирован полный ответ, то есть ответное сообщение.
ответное сообщение
Ответное сообщение в основном состоит из версии протокола, кода состояния, фразы причины, заголовка ответа и тела ответа. Взяв в качестве примера запрос к localhost:5000/hello, ответное сообщение, сгенерированное сервером, показано в следующей таблице:
Описание состава |
Содержание ответного сообщения |
Заголовок сообщения: строка состояния (протокол, код состояния, фраза причины) |
HTTP/1.1 200 OK |
Заголовок сообщения: различные поля заголовка |
Content-Type: text/html; charset=utf-8 Content-Length: 22 Server: Werkzeug/0.12.2 Python/2.7.13 Date: Thu, 03 Aug 2017 05:05:54 GMT ... |
пустая строка |
|
тело сообщения |
<h1>Hello, Human!</h1> |
Заголовок ответного сообщения содержит некоторую информацию об ответе и сервере, который генерируется Flask, а содержимое, которое мы возвращаем в функции просмотра, является содержимым тела ответного сообщения. После того, как браузер получает ответ, он анализирует возвращенное тело ответа и отображает его в окне браузера.
Коды состояния HTTP используются для обозначения результата обработки запроса.В следующей таблице показано несколько распространенных кодов состояния и соответствующие фразы причин:
Сгенерировать ответ в Flask
Ответ представлен объектом Response в Flask. Большая часть содержимого ответного сообщения обрабатывается сервером. В большинстве случаев мы отвечаем только за возврат содержимого тела.
Основываясь на том, что мы описали в разделе запроса, Flask сначала определит, может ли он найти маршрут, соответствующий URL-адресу запроса, и, если нет, вернет ответ 404. Если найдено, вызывается соответствующая функция просмотра.Возвращаемое значение функции просмотра составляет основное содержимое ответного сообщения. Код состояния по умолчанию — 200, когда он возвращается правильно. Flask вызовет метод make_response() для преобразования возвращаемого значения функции представления в объект ответа.
Строго говоря, функция просмотра может возвращать кортеж, состоящий из трех элементов: тела ответа, кода состояния и полей заголовка. Первое поле может быть словарем или списком двухэлементных кортежей.
Например, обычный ответ может содержать только содержимое тела:
@app.route('/hello')
def hello():
...
return '<h1>Hello, Flask!</h1>'
Код состояния по умолчанию — 200, различные коды состояния указаны ниже:
@app.route('/hello')
def hello():
...
return '<h1>Hello, Flask!</h1>', 201
Иногда вам может понадобиться добавить или изменить поле заголовка. Например, чтобы сгенерировать ответ о перенаправлении с кодом состояния 3XX, установите в поле Location в заголовке целевой URL-адрес перенаправления:
@app.route('/hello')
def hello():
...
return '', 302, {'Location': 'http://www.example.com'}
Теперь посетите http://localhost:5000/hello, он будет перенаправлен наwww.example.com. В большинстве случаев, за исключением тела ответа, нам обычно нужно использовать значение по умолчанию только для других частей.
перенаправить
если вы посетитеhttp://localhost:5000/hi, вы обнаружите, что URL-адрес в адресной строке меняется на http://localhost:5000/hello после загрузки страницы. Такое поведение называется перенаправлением, и вы можете понимать его как переход на веб-страницу. В примере из предыдущего раздела тело ответа о перенаправлении с кодом состояния 302 пусто, а в поле «Местоположение» необходимо указать целевой URL-адрес перенаправления в заголовке.После получения ответа о перенаправлении браузер отправит целевой URL-адрес в поле Location на URL-адрес инициирует новый запрос GET, и весь процесс показан на следующем рисунке:
В веб-программах нам часто нужно перенаправлять. Например, когда пользователь обращается к ресурсу, для которого требуется вход без аутентификации, программа обычно перенаправляет на страницу входа.
Для специальных ответов, таких как перенаправления, Flask предоставляет некоторые вспомогательные функции. Вместо ручного создания ответа 302, как раньше, мы можем использовать функцию redirect(), предоставляемую Flask, для создания ответа перенаправления с целевым URL-адресом перенаправления в качестве первого параметра. Предыдущий пример можно упростить до:
from flask import Flask, redirect
...
@app.route('/hello')
def hello():
return redirect('http://www.example.com')
Если вы хотите перенаправить на другие представления в программе, просто используйте функцию url_for() в функции redirect() для создания целевого URL-адреса, например:
from flask import Flask, redirect, url_for
...
@app.route('/hi')
def hi():
...
return redierct(url_for('hello')) # 重定向到/hello
@app.route('/hello')
def hello():
...
ответ об ошибке
Если вы посетите http://localhost:5000/brew/coffee, вы получите сообщение об ошибке 418 (я чайник), как показано ниже:
По большей части Flask автоматически обрабатывает распространенные ответы об ошибках. Классы исключений, соответствующие ошибкам HTTP, определены в модуле werkzeug.exceptions Werkzeug, и соответствующие ответы об ошибках могут быть возвращены путем создания этих исключений. Если вы хотите вручную вернуть ответ об ошибке, удобнее использовать функцию abort(), предоставляемую Flask.
Соответствующий ответ об ошибке можно вернуть, передав код состояния в функцию abort().Следующая функция представления возвращает ответ об ошибке 404:
from flask import Flask, abort
...
@app.route('/404')
def not_found():
abort(404)
Эта статья основана на"Веб-разработка Flask на практике》первыйГлава 2 «Flask и HTTP» сокращена и переписана, полный каталог главПожалуйста, посетите главную страницу книгиhttp://helloflask.com/bookПроверить.