Протоколът HTTP
HTTP представлява прост текстов протокол, който се използва от
услугата WWW за осигуряване на достъп до практически всякакъв вид
данни, наричани събирателно ресурси. В HTTP протокола има понятия
като клиент (обикновено това са Web-браузърите) и сървър (това са
Web-сървърите). Обикновено HTTP протоколът работи върху стандартен
TCP сокет отворен от клиента към сървъра. Стандартният порт за HTTP
протокола e 80, но може да се използва и всеки друг TCP порт.
Комуникацията по HTTP се състои от заявка (request) – съобщение от
клиента към сървъра и отговор (response) – отговор на сървъра на
съобщението от клиента.
В развитието си HTTP протоколът е преминал през версиите 0.9, 1.0 и 1.1, която е най-разпространена. На практика когато се говори за HTTP, обикновено се има предвид HTTP 1.1.
HTTP заявки
HTTP заявката при версия 1.1 на протокола има следния формат:
HTTP заявките имат 3 основни елемента: метод, Request-URI и header-полета.
Методът описва вида на HTTP заявката, изпратена от клиента. Най-често използваните методи са GET и POST. Чрез GET клиентът изисква някакъв ресурс от Web сървъра. POST служи за предаване на данни към сървъра и извличане на ресурс. Имената на методите в HTTP заявките се изписват винаги с главни букви.
Идентификаторът Request-URI определя ресурса, над който ще оперира заявката. В частта Request-URI могат да се използват два вида идентификатори:
- URI идентификатор (Uniform Resource Identifier)
- релативен път спрямо главната директория на Web-сървъра
Един URI идентификатор може да бъде или URL адрес (Uniform Resource Location, например http://www.nakov.com/inetjava/index.html), т.е. да е идентификатор на ресурс, зададен чрез уникалното си местоположение или URN име (Uniform Resource Name, например urn:isbn:954-8905-06-X), т.е. да е идентификатор на ресурс, зададен чрез уникалното си име по даден URN namespace идентификатор (за нашия пример това е идентификатора isbn). В практиката URN схемата за идентификация на ресурс почти не се използва при HTTP заявки.
Релативният път спрямо главната директория на Web-сървъра задава местоположението на ресурс в рамките на текущия Web-сървър. Това е частта от URL, която стои след името на хост-а (сървъра) в URL идентификатора. Например един такъв релативен път може да бъде идентификаторът /inetjava/index.html.
Фрагментът HTTP/1.1 с който завършва първият ред на HTTP заявката задава версията на HTTP протокола, която ще бъде използвана.
Header-полетата от заглавната част задават допълнителни параметри на заявката и определят различни изисквания относно ресурса, който се очаква да бъде върнат от Web-сървъра.
Празният ред определя края на заявката.
Примерна HTTP заявка
Да дадем един пример за HTTP заявка, която връща началната страница от сайта http://www.dir.bg/ :
Как се отличават виртуалните хостове на един Web-сървър
На един Web-сървър може да има хостнати няколко различни сайта, които могат да започват с различни Интернет имена. Такива сайтове се наричат виртуални хостове в рамките на Web-сървъра. Например сайтовете с URL адреси http://www.nakov.com/ и http://bgcon.org/ могат да са хостнати в Web-сървъра на една и съща машина, да кажем машината с IP адрес 194.12.244.90. Възниква въпросът как браузърът указва кой от двата адреса иска, след като те се обслужват от един и същ Web-сървър на една и съща машина.
Ясно е, че в услугата DNS Интернет имената http://www.nakov.com/ и bgcon.org трябва да са регистрирани да съответстват на IP адреса 194.12.244.90. Когато в полето за адрес на един стандартен Web-браузър се напише един от горните два URL адреса, да кажем http://www.nakov.com/, браузърът прави следното: Първо чрез услугата DNS получава IP адреса на машината, която хоства търсения сайт (www.nakov.com). След това отваря TCP връзка към тази машина на порт 80 и изпраща заявка за извличане на ресурса "/". В хедъра на тази заявка браузърът указва в полето Host стойността http://www.nakov.com./ Именно по това поле Host в хедъра на HTTP заявката Web-сървърът разбира за кой от всички виртуални хостове се отнася тази заявка.
Другият начин при HTTP заявка да се укаже виртуалният хост в Web-сървъра е да се използва URI идентификатор на искания ресурс (URL адрес). В този случай името на хоста се включва в самия този идентификатор.
Методи на HTTP заявката
Протоколът HTTP версия 1.1 поддържа общо 8 различни метода: GET, POST, HEAD, PUT, DELETE, OPTIONS, TRACE, CONNECT. Най-често използваните методи са GET и POST и те имат най-голямо значение за Web-програмирането.
HTTP GET заявки
GET методът представлява команда за извличане на ресурс, указан от зададено URI или релативен път в рамките на Web-сървъра. Всичко, което прави Web-сървърът за извличането на статичен ресурс чрез GET заявка е да го прочете от файловата система и да го върне на клиентите в подходящ HTTP отговор. При извличане на динамичен ресурс сървърът изпълнява програмния код, който генерира ресурса и връща резултата от него в HTTP отговор. Ето един реален пример за HTTP заявка с GET метод:
Изпращането на тази заявка към Web-сървъра, който слуша на порт 80 на машината с Интернет адрес inetjava.sourceforge.net, ще върне файла InetJava-2002-program.html от директорията на виртуалния хост inetjava.sourceforge.net.
Тази заявка e съвсем истинска. Тя е генерирана от Web-браузъра Internet Explorer 6.0 при опит да се отиде на URL адрес http://inetjava.sourceforge.net/InetJava-2002-program.html и е прихваната чрез софтуер за подслушване на мрежовия трафик.
При HTTP GET заявката ако към искания ресурс трябва да се зададат параметри, това става като към URI-то се добави въпросителен знак, а след него двойки от вида <име на параметър>=<стойност>, като двойките от този вид се разделят една от друга със &. За избягването на някои непозволени символи се използва така нареченото URL-кодиране, за което ще стане дума по-нататък.
HTTP POST заявки
POST методът служи за изпращане на данни от клиента към Web-сървъра. Обикновено сървърът предава получените от POST заявката данни на някакъв CGI скрипт или вграден модул за динамично генериране на HTML, който ги обработва и връща някакви резултати. Тези резултати се връщат на клиента като отговор на неговата заявка. Ето един реален пример за HTTP заявка с POST метод, изпратена от Internet Explorer 6.0 при опит за влизане в Web-базираната система за електронна поща на адрес http://www.abv.bg/ :
Както се вижда, параметрите се предават след самата заявка, като в header-полетата се указва общата дължина в символи на всички параметри и техните стойности (заедно със символите за край на ред). За разделител между header-полетата и параметрите се използва празен ред. За край на заявката се използва също празен ред. Ако параметрите съдържат непозволени символи, те се кодират по специален начин. Кодирането на параметрите и стойностите им се прави автоматично от Web-браузъра, а разкодирането им съответно от скрипта, който обработва заявката на Web-сървъра.
Отговори на HTTP заявки
На всяка HTTP заявка, независимо дали е валидна или не, Web-сървърът връща някакъв отговор. При валидна заявка за съществуващ ресурс Web-сървърът връща този ресурс, а в противен случай връща код на грешка заедно с текстово описание защо се е получила. Отговорът на HTTP заявка има следния формат:
Първият ред се нарича статус линия и съдържа версията на HTTP протокола, по който се изпраща отговора, трицифрен код на резултата или код на грешка и кратко текстово описание на този код.
Следват header-полетата. Те съдържат различни параметри на върнатия ресурс, както и информация за Web-сървъра.
Следва празен ред, а след него ресурсът, кодиран по описания в header-полетата начин. В зависимост от типа на ресурса, сървърът може да го върне кодиран по различен начин и по различен начин да укаже на клиента колко байта е дълъг HTTP отговорът.
Стойностите на header-полетата и формата на ресурса са от интерес основно за Web-браузъра и затова няма да ги разглеждаме в детайли.
Основното, което трябва да знаем, е че на всяка HTTP заявка сървърът отговаря с HTTP отговор, който съдържа искания ресурс или грешка. Кодовете на грешките започват с цифрата 4 или 5. Кодовете за успешен резултат започват с 2, а кодовете, носещи специална информация – с 3. Най-често срещаните кодове при HTTP отговор са: 200 – успех; 304 – документът не е променян от времето, зададено в header-а (използва се от браузърите при кеширане на документи); 404 – ресурсът не е намерен; 500 – грешка на сървъра. Ето един цялостен пример за изпращане на HTTP заявка за извличане на главната страница от локално стартиран Web-сървър и отговорът на тази заявка:
Както се вижда, сървърът е върнал отговор на HTTP заявката с код 200 (успех) и е върнал искания ресурс. Ето и един пример за неуспешно завършила заявка:
Вижда се, че сървърът освен че връща в отговор на заявката код на грешка 404 изпраща и допълнителна информация, която пояснява значението на този код. Тази информация е във вид на HTML документ, защото е предназначена да бъде показана в браузъра на клиента, който е поискал липсващия ресурс.
Вероятно сте забелязали, че в последния пример използваме заявка по протокол HTTP/1.0, а в предходния – по HTTP/1.1. Най-съществената разликата между двете версии на протокола е, че при HTTP/1.0 след връщането на отговора на HTTP заявка сървърът веднага затваря сокета с клиента, а при HTTP/1.1 може с едно отваряне на сокет да се изпълнят последователно няколко HTTP заявки. Това прави HTTP/1.1 протокола по-бърз заради което е предпочитан от повечето HTTP клиенти.
В развитието си HTTP протоколът е преминал през версиите 0.9, 1.0 и 1.1, която е най-разпространена. На практика когато се говори за HTTP, обикновено се има предвид HTTP 1.1.
HTTP заявки
HTTP заявката при версия 1.1 на протокола има следния формат:
Code:
<метод> <Request-URI> HTTP/1.1 <header-полета> <празен ред>
HTTP заявките имат 3 основни елемента: метод, Request-URI и header-полета.
Методът описва вида на HTTP заявката, изпратена от клиента. Най-често използваните методи са GET и POST. Чрез GET клиентът изисква някакъв ресурс от Web сървъра. POST служи за предаване на данни към сървъра и извличане на ресурс. Имената на методите в HTTP заявките се изписват винаги с главни букви.
Идентификаторът Request-URI определя ресурса, над който ще оперира заявката. В частта Request-URI могат да се използват два вида идентификатори:
- URI идентификатор (Uniform Resource Identifier)
- релативен път спрямо главната директория на Web-сървъра
Един URI идентификатор може да бъде или URL адрес (Uniform Resource Location, например http://www.nakov.com/inetjava/index.html), т.е. да е идентификатор на ресурс, зададен чрез уникалното си местоположение или URN име (Uniform Resource Name, например urn:isbn:954-8905-06-X), т.е. да е идентификатор на ресурс, зададен чрез уникалното си име по даден URN namespace идентификатор (за нашия пример това е идентификатора isbn). В практиката URN схемата за идентификация на ресурс почти не се използва при HTTP заявки.
Релативният път спрямо главната директория на Web-сървъра задава местоположението на ресурс в рамките на текущия Web-сървър. Това е частта от URL, която стои след името на хост-а (сървъра) в URL идентификатора. Например един такъв релативен път може да бъде идентификаторът /inetjava/index.html.
Фрагментът HTTP/1.1 с който завършва първият ред на HTTP заявката задава версията на HTTP протокола, която ще бъде използвана.
Header-полетата от заглавната част задават допълнителни параметри на заявката и определят различни изисквания относно ресурса, който се очаква да бъде върнат от Web-сървъра.
Празният ред определя края на заявката.
Примерна HTTP заявка
Да дадем един пример за HTTP заявка, която връща началната страница от сайта http://www.dir.bg/ :
Code:
GET / HTTP/1.1 Host: www.dir.bg [празен ред]
Как се отличават виртуалните хостове на един Web-сървър
На един Web-сървър може да има хостнати няколко различни сайта, които могат да започват с различни Интернет имена. Такива сайтове се наричат виртуални хостове в рамките на Web-сървъра. Например сайтовете с URL адреси http://www.nakov.com/ и http://bgcon.org/ могат да са хостнати в Web-сървъра на една и съща машина, да кажем машината с IP адрес 194.12.244.90. Възниква въпросът как браузърът указва кой от двата адреса иска, след като те се обслужват от един и същ Web-сървър на една и съща машина.
Ясно е, че в услугата DNS Интернет имената http://www.nakov.com/ и bgcon.org трябва да са регистрирани да съответстват на IP адреса 194.12.244.90. Когато в полето за адрес на един стандартен Web-браузър се напише един от горните два URL адреса, да кажем http://www.nakov.com/, браузърът прави следното: Първо чрез услугата DNS получава IP адреса на машината, която хоства търсения сайт (www.nakov.com). След това отваря TCP връзка към тази машина на порт 80 и изпраща заявка за извличане на ресурса "/". В хедъра на тази заявка браузърът указва в полето Host стойността http://www.nakov.com./ Именно по това поле Host в хедъра на HTTP заявката Web-сървърът разбира за кой от всички виртуални хостове се отнася тази заявка.
Другият начин при HTTP заявка да се укаже виртуалният хост в Web-сървъра е да се използва URI идентификатор на искания ресурс (URL адрес). В този случай името на хоста се включва в самия този идентификатор.
Методи на HTTP заявката
Протоколът HTTP версия 1.1 поддържа общо 8 различни метода: GET, POST, HEAD, PUT, DELETE, OPTIONS, TRACE, CONNECT. Най-често използваните методи са GET и POST и те имат най-голямо значение за Web-програмирането.
HTTP GET заявки
GET методът представлява команда за извличане на ресурс, указан от зададено URI или релативен път в рамките на Web-сървъра. Всичко, което прави Web-сървърът за извличането на статичен ресурс чрез GET заявка е да го прочете от файловата система и да го върне на клиентите в подходящ HTTP отговор. При извличане на динамичен ресурс сървърът изпълнява програмния код, който генерира ресурса и връща резултата от него в HTTP отговор. Ето един реален пример за HTTP заявка с GET метод:
Code:
GET /InetJava-2002-program.html HTTP/1.1 Host: inetjava.sourceforge.net Accept: */* Accept-Language: bg Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0(compatible;MSIE 6.0; Windows NT 5.0) Connection: Keep-Alive Cache-Control: no-cache [празен ред]
Изпращането на тази заявка към Web-сървъра, който слуша на порт 80 на машината с Интернет адрес inetjava.sourceforge.net, ще върне файла InetJava-2002-program.html от директорията на виртуалния хост inetjava.sourceforge.net.
Тази заявка e съвсем истинска. Тя е генерирана от Web-браузъра Internet Explorer 6.0 при опит да се отиде на URL адрес http://inetjava.sourceforge.net/InetJava-2002-program.html и е прихваната чрез софтуер за подслушване на мрежовия трафик.
При HTTP GET заявката ако към искания ресурс трябва да се зададат параметри, това става като към URI-то се добави въпросителен знак, а след него двойки от вида <име на параметър>=<стойност>, като двойките от този вид се разделят една от друга със &. За избягването на някои непозволени символи се използва така нареченото URL-кодиране, за което ще стане дума по-нататък.
HTTP POST заявки
POST методът служи за изпращане на данни от клиента към Web-сървъра. Обикновено сървърът предава получените от POST заявката данни на някакъв CGI скрипт или вграден модул за динамично генериране на HTML, който ги обработва и връща някакви резултати. Тези резултати се връщат на клиента като отговор на неговата заявка. Ето един реален пример за HTTP заявка с POST метод, изпратена от Internet Explorer 6.0 при опит за влизане в Web-базираната система за електронна поща на адрес http://www.abv.bg/ :
Code:
POST /webmail/login.phtml HTTP/1.1 Host: http://www.abv.bg/ Accept: */* Accept-Language: bg Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0(compatible;MSIE 6.0; Windows NT 5.0) Connection: Keep-Alive Cache-Control: no-cache Content-Length: 59 [празен ред] LOGIN_USER=boris DOMAIN_NAME=abv.bg LOGIN_PASS=tajnamajna [празен ред]
Както се вижда, параметрите се предават след самата заявка, като в header-полетата се указва общата дължина в символи на всички параметри и техните стойности (заедно със символите за край на ред). За разделител между header-полетата и параметрите се използва празен ред. За край на заявката се използва също празен ред. Ако параметрите съдържат непозволени символи, те се кодират по специален начин. Кодирането на параметрите и стойностите им се прави автоматично от Web-браузъра, а разкодирането им съответно от скрипта, който обработва заявката на Web-сървъра.
Отговори на HTTP заявки
На всяка HTTP заявка, независимо дали е валидна или не, Web-сървърът връща някакъв отговор. При валидна заявка за съществуващ ресурс Web-сървърът връща този ресурс, а в противен случай връща код на грешка заедно с текстово описание защо се е получила. Отговорът на HTTP заявка има следния формат:
Code:
HTTP/1.1 <код> <текст> <header-полета> <празен ред> <ресурс>
Първият ред се нарича статус линия и съдържа версията на HTTP протокола, по който се изпраща отговора, трицифрен код на резултата или код на грешка и кратко текстово описание на този код.
Следват header-полетата. Те съдържат различни параметри на върнатия ресурс, както и информация за Web-сървъра.
Следва празен ред, а след него ресурсът, кодиран по описания в header-полетата начин. В зависимост от типа на ресурса, сървърът може да го върне кодиран по различен начин и по различен начин да укаже на клиента колко байта е дълъг HTTP отговорът.
Стойностите на header-полетата и формата на ресурса са от интерес основно за Web-браузъра и затова няма да ги разглеждаме в детайли.
Основното, което трябва да знаем, е че на всяка HTTP заявка сървърът отговаря с HTTP отговор, който съдържа искания ресурс или грешка. Кодовете на грешките започват с цифрата 4 или 5. Кодовете за успешен резултат започват с 2, а кодовете, носещи специална информация – с 3. Най-често срещаните кодове при HTTP отговор са: 200 – успех; 304 – документът не е променян от времето, зададено в header-а (използва се от браузърите при кеширане на документи); 404 – ресурсът не е намерен; 500 – грешка на сървъра. Ето един цялостен пример за изпращане на HTTP заявка за извличане на главната страница от локално стартиран Web-сървър и отговорът на тази заявка:
Code:
C:\> telnet localhost 80 GET / HTTP/1.1 Host: localhost [празен ред] HTTP/1.1 200 OK Date: Sat, 10 Aug 2002 16:09:18 GMT Server: Apache/1.3.9 (Win32) Accept-Ranges: bytes Content-Length: 73 Content-Type: text/html [празен ред] <html> <head> <title> Test </title> </head> Test HTML page. </html>
Както се вижда, сървърът е върнал отговор на HTTP заявката с код 200 (успех) и е върнал искания ресурс. Ето и един пример за неуспешно завършила заявка:
Code:
C:\> telnet localhost 80 GET /img/nakov.gif HTTP/1.0 [празен ред] HTTP/1.1 404 Not Found Date: Sat, 10 Aug 2002 16:20:17 GMT Server: Apache/1.3.9 (Win32) Connection: close Content-Type: text/html [празен ред] <HTML><HEAD> <TITLE>404 Not Found</TITLE> </HEAD><BODY> <H1>Not Found</H1> The requested URL /img/nakov.gif was not found on this server.<P> <HR><ADDRESS>Apache/1.3.9 Server at test Port 80</ADDRESS> </BODY></HTML>
Вижда се, че сървърът освен че връща в отговор на заявката код на грешка 404 изпраща и допълнителна информация, която пояснява значението на този код. Тази информация е във вид на HTML документ, защото е предназначена да бъде показана в браузъра на клиента, който е поискал липсващия ресурс.
Вероятно сте забелязали, че в последния пример използваме заявка по протокол HTTP/1.0, а в предходния – по HTTP/1.1. Най-съществената разликата между двете версии на протокола е, че при HTTP/1.0 след връщането на отговора на HTTP заявка сървърът веднага затваря сокета с клиента, а при HTTP/1.1 може с едно отваряне на сокет да се изпълнят последователно няколко HTTP заявки. Това прави HTTP/1.1 протокола по-бърз заради което е предпочитан от повечето HTTP клиенти.