В процессе перевода.

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

Перед стартом: Базовая компьютерная грамотность. Базовое понимание того, что такое веб-сервер.
Цель: Изучить взаимодействие между клиентом и сервером на динамическом веб-сайте и в частности узнать, какие действия нужно произвести в коде серверной части.

В обсуждении нет реального кода, поскольку мы еще не выбрали, какой веб-фреймворк мы будем использовать для написания нашего кода! Это обсуждение, тем не менее, очень актуально, поскольку описанное поведение должно быть реализовано вашим серверным кодом независимо от того, какой язык программирования или веб-фреймворк вы выбираете.

Web-серверы и HTTP (для начинающих)

Веб-браузеры взаимодействуют с веб-серверами при помощи протокола передачи гипертекста (HTTP). Когда вы кликаете на ссылку на странице, заполняете форму или запускаете поиск, браузер отправляет на сервер HTTP-запрос.

Этот запрос включает:

  • Путь, определяющий целевой сервер и ресурс (например, -файл, определенная точка данных на сервере, запускаемый сервис, и т.д.).
  • Метод, который определяет необходимое действие (например, получить файл, сохранить или обновить некоторые данные, и т.д.). Различные методы/команды и связанные с ними действия перечислены ниже:
    • GET– получить определенный ресурс (например, HTML-файл, содержащий информацию о товаре или список товаров).
    • POST– создать новый ресурс (например, новую статью на Википедии, добавить новый контакт в базу данных).
    • HEAD– получить метаданные об определенном ресурсе без получения содержания, как делает GET. Вы, например, можете использовать запрос HEAD, чтобы узнать, когда в последний раз ресурс обновлялся и только потом использовать (более «затратный») запрос GET, чтобы загрузить ресурс, который был изменен.
    • PUT– обновить существующий ресурс (или создать новый, если таковой не существует).
    • DELETE – удалить указанный ресурс.
    • TRACE, OPTIONS, CONNECT, PATCH – эти команды используются для менее популярных/продвинутых задач, поэтому мы их не будем рассматривать.
  • Дополнительная информация может быть зашифрована в запросе (например, данные формы). Информация может быть зашифрована как:
    • Параметры URL: запросы зашифровывают данные в , отправляемую на сервер, добавляя пары имя/значение в его конец, например, http://mysite.com?name=Fred&age=11. У вас всегда есть знак вопроса (?), отделяющий прочую часть от параметров , знак равно (=), отделяющий каждое имя от соответствующего ему значения, и амперсант (&), разделяющий пары. Параметры по своей сути «небезопасны», так как они могут быть изменены пользователями и затем отправлены заново. В результате параметры /запросы не используются для запросов, которые обновляют данные на сервере.
    • POST данные. POST запросы добавляют новые ресурсы, данные которых зашифрованы в теле запроса.
    • Куки-файлы клиентской части. Куки-файлы содержат данные сессий о клиенте, включая ключевые слова, которые сервер может использовать для определения его авторизационный статус и права доступа к ресурсам.

Веб-серверы ожидают сообщений с запросами от клиентов, обрабатывают их, когда они приходят и отвечают веб-браузеру через сообщение с HTTP-ответом. Ответ содержит Код статуса HTTP-ответа, который показывает, был ли запрос успешным (например, «200 OK» означает успех, «404 Not Found» если ресурс не может быть найден, «403 Forbidden», если пользователь не имеет права просматривать ресурс, и т.д.). Тело успешного ответа на запрос GET будет содержать запрашиваемый ресурс.

После того, как HTML страница была возвращена, она обрабатывается браузером. Далее браузер может исследовать ссылки на другие ресурсы (например, HTML страница обычно использует JavaScript и CSS файлы), и послать отдельный HTTP запрос на загрузку этих файлов.

Both static and dynamic websites (discussed in the following sections) use exactly the same communication protocol/patterns.

GET request/response пример

Вы можете сформировать простой GET запрос кликнув по ссылку или через поиск по сайту (например, страница механизма поиска). Например, HTTP  запрос, посланный во время выполнения запроса "client server overview" на сайте MDN, будет во многом похож на текст ниже (он не будет идентичным, потому что части сообщение зависят от Вашего браузера\настроек.

Формат HTTP сообщения определен в веб-стандарте (RFC7230). Вам не нужно знать этот уровень детализации, но, по крайней мере, теперь Вы знаете откуда это появилось!

Запрос

Каждая строка запроса содержит информацию о запросе. Первая часть называется заголовок, он содержит важную информацию о запросе, точно так же как HTML head содержит важную информацию о HTML документе (но не содержимое документа, которое расположено в body):

GET https://developer.mozilla.org/en-US/search?q=client+server+overview&topic=apps&topic=html&topic=css&topic=js&topic=api&topic=webdev HTTP/1.1
Host: developer.mozilla.org
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Referer: https://developer.mozilla.org/en-US/
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: en-US,en;q=0.8,es;q=0.6
Cookie: sessionid=6ynxs23n521lu21b1t136rhbv7ezngie; csrftoken=zIPUJsAZv6pcgCBJSCj1zU6pQZbfMUAT; dwf_section_edit=False; dwf_sg_task_completion=False; _gat=1; _ga=GA1.2.1688886003.1471911953; ffo=true

Первая и вторая строки содержат большую часть информации, о которой говорилось выше:

  • Тип запроса (GET).
  • URL целевого ресурса (/en-US/search).
  • Параметры URL (q=client%2Bserver%2Boverview&topic=apps&topic=html&topic=css&topic=js&topic=api&topic=webdev).
  • Целевой вебсайт (developer.mozilla.org).
  • Конец первой строки так же содержит короткую строку, идентифицирующую версию протокола (HTTP/1.1).

Последняя строка содержит информацию о клиентских куки - в данном случае можно увидеть куки, включающие id для управления сессиями (Cookie: sessionid=6ynxs23n521lu21b1t136rhbv7ezngie; ...).

Оставшиеся строки содержат информацию о используемом браузере и о его некоторых поддерживаемых возможностях Например, здесь Вы можете увидеть:

  • Мой браузер (User-Agent) Mozilla Firefox (Mozilla/5.0).
  • Он может принимать информацию упакованную gzip (Accept-Encoding: gzip).
  • Он может принимать указанные кодировки  (Accept-Charset: ISO-8859-1,UTF-8;q=0.7,*;q=0.7) и языков (Accept-Language: de,en;q=0.7,en-us;q=0.3).
  • Строка Referer идентифицирует адрес веб страницы, содержащей ссыоку еа этот ресурс (т.е. источник оригинального запроса, https://developer.mozilla.org/en-US/).

HTTP запрос так же может содержать body, но в данном случае оно пусто.

Ответ

Первая часть ответа на запрос показана ниже. Заголовок содержит информацию, описанную ниже:

  • Первая строка содержит код ответа 200 OK, говорящий о том, что запрос выполнен успешно.
  • Мы можем видеть, что ответ имеет text/html формат(Content-Type).
  • Так же мы видим, что ответ использует кодировку UTF-8 (Content-Type: text/html; charset=utf-8).
  • Заголовок так же содержит размер ответа (Content-Length: 41823).

В конце сообщения мы видим содержимое body, содержащее HTML код возвращаемого ответа.

HTTP/1.1 200 OK
Server: Apache
X-Backend-Server: developer1.webapp.scl3.mozilla.com
Vary: Accept,Cookie, Accept-Encoding
Content-Type: text/html; charset=utf-8
Date: Wed, 07 Sep 2016 00:11:31 GMT
Keep-Alive: timeout=5, max=999
Connection: Keep-Alive
X-Frame-Options: DENY
Allow: GET
X-Cache-Info: caching
Content-Length: 41823



<!DOCTYPE html>
<html lang="en-US" dir="ltr" class="redesign no-js"  data-ffo-opensanslight=false data-ffo-opensans=false >
<head prefix="og: http://ogp.me/ns#">
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=Edge">
  <script>(function(d) { d.className = d.className.replace(/\bno-js/, ''); })(document.documentElement);</script>
  ...

The remainder of the request includes information about the response (e.g. when it was generated), the server, and how it expects the browser to handle the page (e.g. the X-Frame-Options: DENY line tells the browser not to allow this page to be embedded in an <iframe> in another site).

POST request/response example

An HTTP POST is made when you submit a form containing information to be saved on the server.

The request

The text below shows the HTTP request made when a user submits new profile details on this site. The format of the request is almost the same as the GET request example shown previously, though the first line identifies this request as a POST

POST https://developer.mozilla.org/en-US/profiles/hamishwillee/edit HTTP/1.1
Host: developer.mozilla.org
Connection: keep-alive
Content-Length: 432
Pragma: no-cache
Cache-Control: no-cache
Origin: https://developer.mozilla.org
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Referer: https://developer.mozilla.org/en-US/profiles/hamishwillee/edit
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.8,es;q=0.6
Cookie: sessionid=6ynxs23n521lu21b1t136rhbv7ezngie; _gat=1; csrftoken=zIPUJsAZv6pcgCBJSCj1zU6pQZbfMUAT; dwf_section_edit=False; dwf_sg_task_completion=False; _ga=GA1.2.1688886003.1471911953; ffo=true

csrfmiddlewaretoken=zIPUJsAZv6pcgCBJSCj1zU6pQZbfMUAT&user-username=hamishwillee&user-fullname=Hamish+Willee&user-title=&user-organization=&user-location=Australia&user-locale=en-US&user-timezone=Australia%2FMelbourne&user-irc_nickname=&user-interests=&user-expertise=&user-twitter_url=&user-stackoverflow_url=&user-linkedin_url=&user-mozillians_url=&user-facebook_url=

The main difference is that the URL doesn't have any parameters. As you can see, the information from the form is encoded in the body of the request (for example, the new user fullname is set using: &user-fullname=Hamish+Willee).

The response

The response from the request is shown below. The status code of "302 Found" tells the browser that the post succeeded, and that it must issue a second HTTP request to load the page specified in the Location field. The information is otherwise similar to that for the response to a GET request.

HTTP/1.1 302 FOUND
Server: Apache
X-Backend-Server: developer3.webapp.scl3.mozilla.com
Vary: Cookie
Vary: Accept-Encoding
Content-Type: text/html; charset=utf-8
Date: Wed, 07 Sep 2016 00:38:13 GMT
Location: https://developer.mozilla.org/en-US/profiles/hamishwillee
Keep-Alive: timeout=5, max=1000
Connection: Keep-Alive
X-Frame-Options: DENY
X-Cache-Info: not cacheable; request wasn't a GET or HEAD
Content-Length: 0

Note: The HTTP responses and requests shown in these examples were captured using the Fiddler application, but you can get similar information using web sniffers (e.g. http://web-sniffer.net/) or using browser extensions like HttpFox. You can try this yourself. Use any of the linked tools, and then navigate through a site and edit profile information to see the different requests and responses. Most modern browsers also have tools that monitor network requests (for example, the Network Monitor tool in Firefox).

Static sites

A static site is one that returns the same hard coded content from the server whenever a particular resource is requested. So for example if you have a page about a product at /static/myproduct1.html , this same page will be returned to every user. If you add another similar product to your site you will need to add another page (e.g. myproduct2.html) and so on. This can start to get really inefficient — what happens when you get to thousands of product pages? You would repeat a lot of code across each page (the basic page template, structure, etc.), and if you wanted to change anything about the page structure — like add a new "related products" section for example — then you'd have to change every page individually. 

Note: Static sites are excellent when you have a small number of pages and you want to send the same content to every user. However they can have a significant cost to maintain as the number of pages becomes larger.

Let's recap on how this works, by looking again at the static site architecture diagram we looked at in the last article.

A simplified diagram of a static web server.

When a user wants to navigate to a page, the browser sends an HTTP GET request specifying the URL of its HTML page. The server retrieves the requested document from its file system and returns an HTTP response containing the document and an HTTP Response status code of "200 OK" (indicating success). The server might return a different status code, for example "404 Not Found" if the file is not present on the server, or "301 Moved Permanently" if the file exists but has been redirected to a different location.

The server for a static site will only ever need to process GET requests, because the server doesn't store any modifiable data. It also doesn't change its responses based on HTTP Request data (e.g. URL parameters or cookies). 

Understanding how static sites work is nevertheless useful when learning server-side programming, because dynamic sites handle requests for static files (CSS, JavaScript, static images, etc.) in exactly the same way.

Dynamic sites

A dynamic site is one that can generate and return content based on the specific request URL and data (rather than always returning the same hard-coded file for a particular URL). Using the example of a product site, the server would store product "data" in a database rather than individual HTML files. When receiving an HTTP GET Request for a product, the server determines the product ID, fetches the data from the database, and then constructs the HTML page for the response by inserting the data into an HTML template. This has major advantages over a static site:

Using a database allows the product information to be stored efficiently in an easily extensible, modifiable, and searchable way.

Using HTML templates makes it very easy to change the HTML structure, because this only needs to be done in one place, in a single template, and not across potentially thousands of static pages.

Anatomy of a dynamic request

This section provides a step-by-step overview of the "dynamic" HTTP request and response cycle, building on what we looked at in the last article with much more detail. In order to "keep things real" we'll use the context of a sports-team manager website where a coach can select their team name and team size in an HTML form and get back a suggested "best lineup" for their next game. 

The diagram below shows the main elements of the "team coach" website, along with numbered labels for the sequence of operations when the coach accesses their "best team" list. The parts of the site that make it dynamic are the Web Application (this is how we will refer to the server-side code that processes HTTP requests and returns HTTP responses), the Database, which contains information about players, teams, coaches and their relationships, and the HTML Templates.

This is a diagram of a simple web server with step numbers for each of step of the client-server interaction.

After the coach submits the form with the team name and number of players, the sequence of operations is:

  1. The web browser creates an HTTP GET request to the server using the base URL for the resource (/best) and encoding the team and player number either as URL parameters (e.g. /best?team=my_team_name&show=11) or as part of the URL pattern (e.g. /best/my_team_name/11/). A GET request is used because the request is only fetching data (not modifying data).
  2. The Web Server detects that the request is "dynamic" and forwards it to the Web Application for processing (the web server determines how to handle different URLs based on pattern matching rules defined in its configuration).
  3. The Web Application identifies that the intention of the request is to get the "best team list" based on the URL (/best/) and finds out the required team name and number of players from the URL. The Web Application then gets the required information from the database (using additional "internal" parameters to define which players are "best", and possibly also getting the identity of the logged in coach from a client-side cookie).
  4. The web application dynamically creates an HTML page by putting the data (from the database) into placeholders inside an HTML template.
  5. The Web Application returns the generated HTML to the web browser (via the Web Server), along with an HTTP status code of 200 ("success"). If anything prevents the HTML being returned then the Web Application will return another code — for example "404" to indicate that the team does not exist.
  6. The Web Browser will then start to process the returned HTML, sending separate requests to get any other CSS or JavaScript files that it references (see step 7).
  7. The Web Server loads static files from the file system and returns them to the browser directly (again, correct file handling is based on configuration rules and URL pattern matching).

An operation to update a record in the database would be handled similarly, except that like any database update, the HTTP request from the browser should be encoded as a POST request. 

Doing other work

A Web Application's job is to receive HTTP requests and return HTTP responses. While interacting with a database to get or update information are very common tasks, the code may do other things at the same time, or not interact with a database at all.

A good example of an additional task that a Web Application might perform would be sending an email to users to confirm their registration with the site. The site might also perform logging or other operations. 

Returning something other than HTML

Server-side website code does not have to return HTML snippets/files in the response. It can instead dynamically create and return other types of files (text, PDF, CSV, etc.) or even data (JSON, XML, etc.).

The idea of returning data to a web browser so that it can dynamically update its own content (AJAX) has been around for quite a while. More recently "Single-page apps" have become popular, where the whole website is written with a single HTML file that is dynamically updated when needed. Websites created using this style of application push a lot of computational cost from the server to the web browser, and can result in websites that appear to behave a lot more like native apps (highly responsive, etc.).

Web frameworks simplify server-side web programming

Server-side web frameworks make writing code to handle the operations described above much easier.

One of the most important operations they perform is providing simple mechanisms to map URLs for different resources/pages to specific handler functions. This makes it easier to keep the code associated with each type of resource separate. It also has benefits in terms of maintenance, because you can change the URL used to deliver a particular feature in one place, without having to change the handler function.

For example, consider the following Django (Python) code that maps two URL patterns to two view functions. The first pattern ensures that an HTTP request with a resource URL of /best will be passed to a function named index() in the views module. A request that has the pattern "/best/junior", will instead be passed to the junior() view function.

# file: best/urls.py
#

from django.conf.urls import url

from . import views

urlpatterns = [
    # example: /best/
    url(r'^$', views.index),
    # example: /best/junior/
    url(r'^junior/$', views.junior),
]

Note: The first parameters in the url() functions may look a bit odd (e.g. r'^junior/$') because they use a pattern matching technique called "regular expressions" (RegEx, or RE). You don't need to know how regular expressions work at this point, other than that they allow us to match patterns in the URL (rather than the hard coded values above) and use them as parameters in our view functions. As an example, a really simple RegEx might say "match a single uppercase letter, followed by between 4 and 7 lower case letters."

The web framework also makes it easy for a view function to fetch information from the database. The structure of our data is defined in models, which are Python classes that define the fields to be stored in the underlying database. If we we have a model named Team with a field of "team_type" then we can use a simple query syntax to get back all teams that have a particular type.

The example below gets a list of all teams that have the exact (case sensitive) team_type of "junior" — note the format: field name (team_type) followed by double underscore, and then the type of match to use (in this case exact). There are many other types of matches and we can daisy chain them. We can also control the order and the number of results returned. 

#best/views.py

from django.shortcuts import render

from .models import Team 


def junior(request):
    list_teams = Team.objects.filter(team_type__exact="junior")
    context = {'list': list_teams}
    return render(request, 'best/index.html', context)

After the junior() function gets the list of junior teams, it calls the render() function, passing the original HttpRequest, an HTTP template, and a "context" object defining the information to be included in the template. The  render() function is a convenience function that generates HTML using a context and an HTML template, and returns it in an HttpResponse object.

Obviously web frameworks can help you with a lot of other tasks. We discuss a lot more benefits and some popular web framework choices in the next article.

Summary

At this point you should have a good overview of the operations that server-side code has to perform, and know some of the ways in which a server-side web framework can make this easier.

In a following module we'll help you choose the best Web Framework for your first site.

Метки документа и участники

 Внесли вклад в эту страницу: Limpar, Teexy, joisadler, ElenaMazurik, Khulagen
 Обновлялась последний раз: Limpar,