HTTP/2 sari yo'l
HTTP evolyutsiyasi. Hammasi qanday boshlangan va bugun qayerda turibmiz
Muallif: Kamran Ahmed
HTTP — har bir veb-dasturchi bilishi kerak bo'lgan protokol, chunki butun veb aynan u bilan ishlaydi va uni bilish sizga albatta yaxshiroq ilovalar yaratishda yordam beradi. Ushbu qo'llanmada HTTP nima ekani, u qanday paydo bo'lgani, bugun qayerda turgani va bu yerga qanday yetib kelganimiz haqida gaplashaman.
HTTP nima?
Eng avvalo, HTTP nima? HTTP — TCP/IP asosidagi application layer aloqa protokoli bo'lib, u client va server bir-biri bilan qanday muloqot qilishini standartlashtiradi. U kontent internet orqali qanday so'ralishi va uzatilishini belgilaydi. Application layer protokoli deganda men host'lar (client'lar va server'lar) qanday muloqot qilishini standartlashtiradigan shunchaki abstraction qatlamini nazarda tutyapman; uning o'zi esa client va server o'rtasida so'rov va javob almashish uchun TCP/IP'ga tayanadi. Default holatda TCP port 80 ishlatiladi, lekin boshqa portlardan ham foydalanish mumkin. HTTPS esa 443 portdan foydalanadi.
HTTP/0.9 – bir qatorli protokol (1991)
HTTP'ning birinchi hujjatlashtirilgan versiyasi 1991-yilda taklif qilingan HTTP/0.9 edi. Bu hozirgacha bo'lgan eng oddiy protokol bo'lib, unda GET deb ataladigan yagona method bor edi. Agar client serverdagi biror veb-sahifaga kirishi kerak bo'lsa, u quyidagidek oddiy so'rov yuborardi
GET /index.html
Serverdan keladigan javob esa quyidagicha ko'rinishda bo'lardi
(response body) (connection closed)
Ya'ni server so'rovni qabul qilib, javobda HTML qaytarardi va kontent uzatilishi bilanoq ulanish yopilardi. Unda
- Header'lar yo'q edi
GETyagona ruxsat etilgan method edi- Javob HTML bo'lishi shart edi
Ko'rib turganingizdek, bu protokol aslida keyin keladigan narsalar uchun bir pog'ona bo'lishdan boshqa hech narsa emas edi.
HTTP/1.0 - 1996
1996-yilda HTTP'ning keyingi versiyasi, ya'ni HTTP/1.0 paydo bo'ldi va u asl versiyaga nisbatan ancha yaxshilangan edi.
Faqat HTML javob uchun mo'ljallangan HTTP/0.9'dan farqli o'laroq, HTTP/1.0 endi boshqa javob formatlari, ya'ni rasmlar, video fayllar, oddiy matn yoki istalgan boshqa content type bilan ham ishlay olardi. Unga ko'proq method'lar (ya'ni POST va HEAD) qo'shildi, so'rov/javob formatlari o'zgardi, so'rovlarga ham, javoblarga ham HTTP header'lar qo'shildi, javobni aniqlash uchun status code'lar qo'shildi, character set qo'llab-quvvatlash joriy qilindi, shuningdek multi-part type'lar, authorization, keshlash, content encoding va boshqa ko'p narsalar kiritildi.
Namunaviy HTTP/1.0 so'rovi va javobi quyidagicha ko'rinishda bo'lishi mumkin edi:
GET / HTTP/1.0 Host: kamranahmed.info User-Agent: Mozilla/5.0 (Macintosh; Intel
Mac OS X 10_10_5) Accept: */*
Ko'rib turganingizdek, so'rov bilan birga client o'zining shaxsiy ma'lumotlari, talab qilinadigan javob turi va hokazolarni ham yubordi. HTTP/0.9'da esa client bunday ma'lumotlarni hech qachon yubora olmasdi, chunki header'lar yo'q edi.
Yuqoridagi so'rovga javob namunasi quyidagicha ko'rinishda bo'lishi mumkin edi
HTTP/1.0 200 OK Content-Type: text/plain Content-Length: 137582 Expires: Thu, 05
Dec 1997 16:00:00 GMT Last-Modified: Wed, 5 August 1996 15:55:28 GMT Server:
Apache 0.84 (response body) (connection closed)
Javobning eng boshida HTTP/1.0 (HTTP va undan keyin versiya raqami), so'ng 200 status code'i va undan keyin reason phrase (yoki, xohlasangiz, status code'ning tavsifi) keladi.
Bu yangi versiyada so'rov va javob header'lari hali ham ASCII encoding'da saqlangan, lekin javob body'si istalgan turda, ya'ni rasm, video, HTML, oddiy matn yoki istalgan boshqa content type bo'lishi mumkin edi. Shunday qilib, endi server client'ga istalgan content type'ni yubora olgani sababli, joriy qilinganidan ko'p o'tmay HTTP'dagi "Hyper Text" atamasi o'z ma'nosiga mos kelmay qoldi. HMTP yoki Hypermedia transfer protocol ko'proq ma'noga ega bo'lishi mumkin edi, lekin, menimcha, biz bu nom bilan umrbod qolib ketdik.
HTTP/1.0'ning asosiy kamchiliklaridan biri — bitta ulanishda bir nechta so'rov yuborib bo'lmasligi edi. Ya'ni client'ga serverdan biror narsa kerak bo'lganida, u yangi TCP ulanishini ochishi kerak bo'lardi va o'sha yagona so'rov bajarilgandan keyin ulanish yopilardi. Keyingi har qanday ehtiyoj uchun esa yangi ulanish kerak bo'lardi. Nega bu yomon? Aytaylik, siz 10 ta rasm, 5 ta stylesheet va 5 ta javascript faylga ega veb-sahifaga kirdingiz, ya'ni o'sha veb-sahifaga so'rov yuborilganda jami 20 ta element olinishi kerak. Server so'rov bajarilishi bilanoq ulanishni yopgani uchun ketma-ket 20 ta alohida ulanish bo'ladi va elementlarning har biri o'z alohida ulanishida birin-ketin uzatiladi. Bunday ko'p sonli ulanishlar unumdorlikka jiddiy zarba beradi, chunki yangi TCP ulanishini talab qilish three-way handshake va undan keyingi slow-start tufayli unumdorlikka sezilarli jarima yuklaydi.
Three-way Handshake
Eng oddiy ko'rinishida three-way handshake shundan iboratki, barcha TCP ulanishlari three-way handshake bilan boshlanadi: unda client va server application ma'lumotlarini almashishni boshlashdan oldin bir qator paketlar almashadi.
SYN- Client tasodifiy son tanlaydi, aytaylikx, va uni serverga yuboradi.SYN ACK- Server so'rovni tasdiqlab, client'gaACKpaketini qaytaradi; bu paket server tanlagan tasodifiy son, aytayliky, vax+1sonidan iborat bo'ladi, bu yerdax— client yuborgan sonACK- Client serverdan olganysonini bittaga oshiradi vay+1soni bilanACKpaketini qaytaradi
Three-way handshake tugagach, client va server o'rtasida ma'lumot almashish boshlanishi mumkin. Shuni ta'kidlash kerakki, client oxirgi ACK paketini jo'natishi bilanoq application ma'lumotlarini yuborishni boshlashi mumkin, lekin server so'rovni bajarish uchun baribir ACK paketi kelishini kutishi kerak bo'ladi.

E'tibor bering, rasmda kichik xato bor: handshake'ni yakunlash uchun client yuborgan oxirgi
ACKpaketida faqaty+1bo'ladi, ya'ni uACK: x+1, y+1o'rnigaACK:y+1bo'lishi kerak edi
Biroq HTTP/1.0'ning ba'zi implementatsiyalari Connection: keep-alive deb ataladigan yangi header'ni joriy qilish orqali bu muammoni yengishga harakat qildi; u serverga "Hey server, bu ulanishni yopma, u menga yana kerak" deyish uchun mo'ljallangan edi. Ammo baribir u unchalik keng qo'llab-quvvatlanmadi va muammo saqlanib qoldi.
Connection-less bo'lishdan tashqari, HTTP yana stateless protokol hamdir, ya'ni server client haqidagi ma'lumotni saqlamaydi, shuning uchun har bir so'rovda server uni hech qanday eski so'rovlarga bog'lamasdan mustaqil bajarishi uchun zarur ma'lumot bo'lishi kerak. Bu esa olovga moy sepadi: client ochishi kerak bo'lgan ko'p sonli ulanishlardan tashqari, u tarmoq orqali ortiqcha ma'lumotlarni ham yuborishi kerak bo'ladi, bu esa bandwidth sarfini oshiradi.
HTTP/1.1 - 1999
HTTP/1.0'dan bor-yo'g'i 3 yil o'tib, 1999-yilda keyingi versiya, ya'ni HTTP/1.1 chiqdi; u o'zidan oldingi versiyaga nisbatan ko'plab yaxshilanishlar kiritdi. HTTP/1.0'ga nisbatan asosiy yaxshilanishlar quyidagilarni o'z ichiga oldi
-
Yangi HTTP method'lar qo'shildi:
PUT,PATCH,OPTIONS,DELETEjoriy qilindi -
Hostname Identification
HTTP/1.0'daHostheader'i majburiy emas edi, lekinHTTP/1.1uni majburiy qildi. -
Persistent Connections Yuqorida aytib o'tilganidek,
HTTP/1.0'da har bir ulanishda faqat bitta so'rov bo'lar va so'rov bajarilishi bilanoq ulanish yopilardi, bu esa unumdorlikka jiddiy zarba va latency muammolariga olib kelardi.HTTP/1.1persistent connection'larni joriy qildi, ya'ni ulanishlar default holatda yopilmasdi va ochiq qoldirilardi, bu esa bir nechta ketma-ket so'rov yuborishga imkon berdi. Ulanishlarni yopish uchun so'rovdaConnection: closeheader'i bo'lishi kerak edi. Client'lar odatda ulanishni xavfsiz yopish uchun bu header'ni oxirgi so'rovda yuboradi. -
Pipelining U pipelining'ni qo'llab-quvvatlashni ham joriy qildi: bunda client bitta ulanishda serverdan javob kutmasdan serverga bir nechta so'rov yubora olardi, server esa javoblarni so'rovlar qabul qilingan tartibda yuborishi kerak edi. Lekin client birinchi javobni yuklab olish qayerda tugashini va keyingi javob kontenti qayerdan boshlanishini qanday biladi, deb so'rashingiz mumkin! Buni hal qilish uchun
Content-Lengthheader'i bo'lishi kerak; client'lar undan javob qayerda tugashini aniqlash va keyingi javobni kutishni boshlash uchun foydalanishi mumkin.Shuni ta'kidlash kerakki, persistent connection'lar yoki pipelining'dan foyda olish uchun javobda
Content-Lengthheader'i bo'lishi shart, chunki u client'ga uzatish qachon tugashini bildiradi va shunda client keyingi so'rovni yuborishi (so'rovlarni oddiy ketma-ket yuborish usulida) yoki keyingi javobni kutishni boshlashi (pipelining yoqilgan bo'lsa) mumkin bo'ladi.Ammo bu yondashuvda hali ham bir muammo bor edi. U shundaki, agar ma'lumot dinamik bo'lsa va server kontent uzunligini oldindan aniqlay olmasa-chi? Bunday holda persistent connection'lardan haqiqatan ham foyda ololmaysiz, to'g'rimi?! Buni hal qilish uchun
HTTP/1.1chunked encoding'ni joriy qildi. Bunday hollarda server chunked encoding foydasiga content-Length'ni tushirib qoldirishi mumkin (bu haqda birozdan keyin batafsil). Biroq agar ularning hech biri mavjud bo'lmasa, so'rov oxirida ulanish yopilishi kerak. -
Chunked Transfers Dinamik kontent holatida, server uzatish boshlanganda
Content-Length'ni aniqlay olmasa, u kontentni bo'laklab (chunk'ma-chunk) yuborishni boshlashi va har bir chunk yuborilganda ungaContent-Lengthqo'shishi mumkin. Barcha chunk'lar yuborilgach, ya'ni butun uzatish tugagach, client'ga uzatish tugaganini bildirish uchun u bo'sh chunk'ni, ya'niContent-Lengthnolga teng bo'lgan chunk'ni yuboradi. Client'ni chunked transfer haqida xabardor qilish uchun serverTransfer-Encoding: chunkedheader'ini qo'shadi -
Faqat Basic authentication'ga ega bo'lgan
HTTP/1.0'dan farqli o'laroq,HTTP/1.1digest va proxy authentication'ni ham o'z ichiga oldi -
Keshlash
-
Byte Ranges
-
Character set'lar
-
Language negotiation
-
Client cookie'lari
-
Kengaytirilgan compression qo'llab-quvvatlashi
-
Yangi status code'lar
-
..va boshqalar
Ushbu postda HTTP/1.1'ning barcha imkoniyatlari ustida to'xtalib o'tirmayman, chunki bu alohida mavzu va siz u haqda allaqachon ko'p ma'lumot topishingiz mumkin. O'qishingizni tavsiya qiladigan shunday hujjatlardan biri — Key differences between HTTP/1.0 and HTTP/1.1, eng tirishqoqlar uchun esa mana asl RFC'ga havola.
HTTP/1.1 1999-yilda joriy qilingan va ko'p yillar davomida standart bo'lib keldi. U o'zidan oldingisiga nisbatan ancha yaxshilangan bo'lsa-da, veb har kuni o'zgarib borar ekan, u eskira boshladi. Hozirgi kunda veb-sahifani yuklash har qachongidan ham ko'proq resurs talab qiladi. Bugungi oddiy veb-sahifa 30 tadan ortiq ulanish ochishi kerak. Axir HTTP/1.1'da persistent connection'lar bor, unda nega shuncha ko'p ulanish? deysiz! Sababi shundaki, HTTP/1.1'da istalgan paytda faqat bitta yakunlanmagan ulanish bo'lishi mumkin. HTTP/1.1 pipelining'ni joriy qilish orqali buni tuzatishga harakat qildi, lekin head-of-line blocking tufayli muammoni to'liq hal qila olmadi: bunda sekin yoki og'ir so'rov o'zidan keyingi so'rovlarni bloklab qo'yishi mumkin va so'rov pipeline'da tiqilib qolgach, u keyingi so'rovlar bajarilishini kutishi kerak bo'ladi. HTTP/1.1'ning bu kamchiliklarini yengish uchun dasturchilar turli aylanma yechimlarni qo'llay boshladi, masalan, spritesheet'lardan foydalanish, CSS ichiga encode qilingan rasmlar, bitta ulkan CSS/Javascript fayllar, domain sharding va hokazo.
SPDY - 2009
Google oldinga qadam tashlab, vebni tezroq qilish va veb xavfsizligini yaxshilash bilan birga veb-sahifalar latency'sini kamaytirish uchun muqobil protokollar bilan tajriba o'tkazishni boshladi. 2009-yilda ular SPDY'ni e'lon qildi.
SPDY— Google'ning savdo belgisi va u qisqartma emas.
Ma'lum bo'lishicha, agar bandwidth'ni oshirishda davom etsak, boshida tarmoq unumdorligi oshadi, lekin shunday nuqta keladiki, unumdorlikda deyarli o'sish bo'lmaydi. Ammo xuddi shuni latency bilan qilsangiz, ya'ni latency'ni kamaytirishda davom etsak, unumdorlik doimiy ravishda oshib boradi. SPDY ortidagi unumdorlikni oshirishning asosiy g'oyasi ham shu edi: tarmoq unumdorligini oshirish uchun latency'ni kamaytirish.
Farqni bilmaganlar uchun: latency — bu kechikish, ya'ni ma'lumot manba va manzil o'rtasida qancha vaqtda yetib borishi (millisekundlarda o'lchanadi), bandwidth esa sekundiga uzatiladigan ma'lumot miqdori (sekundiga bitlarda).
SPDY imkoniyatlari qatoriga multiplexing, compression, prioritization, xavfsizlik va boshqalar kirardi. SPDY tafsilotlariga kirishmayman, chunki keyingi bo'limda HTTP/2'ning nozik jihatlariga kirishganimizda tasavvurga ega bo'lasiz — aytganimdek, HTTP/2 asosan SPDY'dan ilhomlangan.
SPDY aslida HTTP'ni almashtirishga urinmadi; u HTTP ustidagi, application layer'da mavjud bo'lgan translation qatlami bo'lib, so'rovni tarmoqqa yuborishdan oldin o'zgartirardi. U de-fakto standartga aylana boshladi va brauzerlarning aksariyati uni implementatsiya qila boshladi.
2015-yilda Google'dagilar ikkita raqobatlashuvchi standartga ega bo'lishni xohlamadi va shuning uchun uni HTTP'ga birlashtirib, HTTP/2'ni dunyoga keltirishga va SPDY'ni deprecate qilishga qaror qildi.
HTTP/2 - 2015
Endi siz HTTP protokolining yana bir tahriri nega kerak bo'lganiga ishonch hosil qilgan bo'lsangiz kerak. HTTP/2 kontentni past latency bilan uzatish uchun ishlab chiqilgan. Uning asosiy imkoniyatlari yoki eski HTTP/1.1 versiyasidan farqlari quyidagilarni o'z ichiga oladi
- Matnli o'rniga binary
- Multiplexing - bitta ulanish orqali bir nechta asinxron HTTP so'rovlari
- HPACK yordamida header compression
- Server Push - bitta so'rovga bir nechta javob
- Request Prioritization
- Xavfsizlik

1. Binary protokol
HTTP/2 binary protokol bo'lish orqali HTTP/1.x'da mavjud bo'lgan latency oshishi muammosini hal qilishga intiladi. Binary protokol bo'lgani uchun uni parse qilish osonroq, lekin HTTP/1.x'dan farqli o'laroq, endi uni inson ko'zi bilan o'qib bo'lmaydi. HTTP/2'ning asosiy qurilish bloklari — frame'lar va stream'lar
Frame'lar va stream'lar
HTTP xabarlari endi bir yoki bir nechta frame'dan tashkil topadi. Metadata uchun HEADERS frame'i va payload uchun DATA frame'i bor, shuningdek boshqa bir nechta frame turlari ham mavjud (HEADERS, DATA, RST_STREAM, SETTINGS, PRIORITY va hokazo), ularni HTTP/2 spetsifikatsiyalari orqali ko'rib chiqishingiz mumkin.
Har bir HTTP/2 so'rovi va javobiga noyob stream ID beriladi va u frame'larga bo'linadi. Frame'lar — binary ma'lumot bo'laklaridan boshqa narsa emas. Frame'lar to'plami Stream deb ataladi. Har bir frame'da u tegishli bo'lgan stream'ni aniqlaydigan stream id bor va har bir frame umumiy header'ga ega. Shuningdek, stream ID noyob bo'lishidan tashqari, shuni aytib o'tish joizki, client boshlagan har qanday so'rov toq sonlardan, serverdan keladigan javob esa juft sonli stream ID'lardan foydalanadi.
HEADERS va DATA'dan tashqari, menimcha, bu yerda tilga olishga arziydigan yana bir frame turi — RST_STREAM; bu biror stream'ni bekor qilish uchun ishlatiladigan maxsus frame turi, ya'ni client bu frame'ni yuborib, serverga bu stream endi kerak emasligini bildirishi mumkin. HTTP/1.1'da serverni client'ga javob yuborishni to'xtatishga majbur qilishning yagona yo'li ulanishni yopish edi, bu esa latency oshishiga olib kelardi, chunki keyingi har qanday so'rov uchun yangi ulanish ochilishi kerak edi. HTTP/2'da esa client RST_STREAM'dan foydalanib, muayyan stream'ni qabul qilishni to'xtatishi mumkin, ulanish esa ochiq qoladi va boshqa stream'lar ishlashda davom etadi.
2. Multiplexing
HTTP/2 endi binary protokol bo'lgani va yuqorida aytganimdek, so'rovlar va javoblar uchun frame'lar va stream'lardan foydalangani sababli, TCP ulanishi ochilgach, barcha stream'lar qo'shimcha ulanishlar ochmasdan aynan shu ulanish orqali asinxron tarzda yuboriladi. O'z navbatida server ham xuddi shunday asinxron tarzda javob beradi, ya'ni javobda tartib yo'q va client muayyan paket qaysi stream'ga tegishli ekanini aniqlash uchun berilgan stream id'dan foydalanadi. Bu HTTP/1.x'da mavjud bo'lgan head-of-line blocking muammosini ham hal qiladi, ya'ni client ko'p vaqt olayotgan so'rovni kutib turishi shart emas va boshqa so'rovlar baribir qayta ishlanaveradi.
3. HPACK Header Compression
Bu yuboriladigan header'larni optimallashtirishga maxsus qaratilgan alohida RFC'ning bir qismi edi. Uning mohiyati shundaki, biz bitta client'dan serverga doimiy murojaat qilganimizda, header'larda qayta-qayta yuboradigan ortiqcha ma'lumotlar juda ko'p bo'ladi, ba'zan esa header'lar hajmini oshiradigan cookie'lar ham bo'lishi mumkin, bu esa bandwidth sarfi va latency oshishiga olib keladi. Buni yengish uchun HTTP/2 header compression'ni joriy qildi.

So'rov va javobdan farqli o'laroq, header'lar gzip yoki compress kabi formatlarda siqilmaydi, balki header compression uchun boshqa mexanizm ishlatiladi: literal qiymatlar Huffman code yordamida encode qilinadi, client va server headers jadvalini yuritadi hamda client ham, server ham keyingi so'rovlarda takrorlanuvchi header'larni (masalan, user agent va hokazo) tushirib qoldiradi va ularga ikkala tomon yuritadigan headers jadvali orqali murojaat qiladi.
Header'lar haqida gap ketar ekan, shuni qo'shimcha qilay: ba'zi pseudo header'lar, ya'ni :method, :scheme, :host va :path qo'shilganini hisobga olmasa, header'lar hali ham HTTP/1.1'dagi bilan bir xil.
4. Server Push
Server push — HTTP/2'ning yana bir ajoyib imkoniyati: bunda server client muayyan resursni so'rashini bilgan holda, client so'ramasdan turib uni client'ga push qilishi mumkin. Masalan, aytaylik, brauzer veb-sahifani yuklayapti; u serverdan yuklashi kerak bo'lgan tashqi kontentni aniqlash uchun butun sahifani parse qiladi va so'ng o'sha kontentni olish uchun serverga ketma-ket so'rovlar yuboradi.
Server push server'ga client talab qilishini bilgan ma'lumotlarni push qilish orqali round trip'larni kamaytirish imkonini beradi. Bu qanday amalga oshiriladi: server PUSH_PROMISE deb ataladigan maxsus frame yuborib, client'ga "Hey, men senga bu resursni yubormoqchiman! Uni mendan so'rama." deb xabar beradi. PUSH_PROMISE frame'i push sodir bo'lishiga sabab bo'lgan stream bilan bog'langan bo'ladi va u va'da qilingan stream ID'ni, ya'ni server push qilinadigan resursni yuboradigan stream'ni o'z ichiga oladi.
5. Request Prioritization
Client stream ochiladigan HEADERS frame'iga prioritization ma'lumotini kiritib, stream'ga priority belgilashi mumkin. Istalgan boshqa vaqtda client stream priority'sini o'zgartirish uchun PRIORITY frame'ini yuborishi mumkin.
Hech qanday priority ma'lumoti bo'lmasa, server so'rovlarni asinxron, ya'ni hech qanday tartibsiz qayta ishlaydi. Agar stream'ga priority belgilangan bo'lsa, server shu prioritization ma'lumotiga asoslanib, qaysi so'rovni qayta ishlashga qancha resurs ajratish kerakligini hal qiladi.
6. Xavfsizlik
HTTP/2 uchun xavfsizlikni (TLS orqali) majburiy qilish kerakmi yoki yo'qmi, degan masalada keng muhokamalar bo'ldi. Oxir-oqibat uni majburiy qilmaslikka qaror qilindi. Biroq ko'pchilik vendor'lar HTTP/2'ni faqat TLS ustida ishlatilganda qo'llab-quvvatlashini ma'lum qildi. Shunday qilib, HTTP/2 spetsifikatsiya bo'yicha encryption'ni talab qilmasa-da, baribir default holatda deyarli majburiy bo'lib qoldi. Shuni aytib o'tgach, TLS ustida implementatsiya qilingan HTTP/2 ba'zi talablarni qo'yadi, ya'ni TLS'ning 1.2 yoki undan yuqori versiyasi ishlatilishi kerak, kalitlarning ma'lum minimal o'lchami bo'lishi kerak, ephemeral key'lar talab qilinadi va hokazo.
HTTP/2 allaqachon shu yerda va u qo'llanilish bo'yicha SPDY'dan o'zib ketgan, qo'llanilishi esa asta-sekin o'sib bormoqda. HTTP/2 unumdorlikni oshirish nuqtai nazaridan ko'p narsa taklif qiladi va undan foydalanishni boshlash vaqti allaqachon keldi.
Batafsil ma'lumotga qiziquvchilar uchun mana spetsifikatsiyalarga havola va HTTP/2'ning unumdorlik afzalliklarini namoyish etuvchi havola.
Mana, gap shu yerda tugaydi. Keyingi safargacha! Biz bilan qoling.