prefață
Protocolul HTTP este unul dintre cele mai importante protocoale de pe Internet, deși pare simplu, dar în practică întâmpină adesea probleme și l-am întâlnit de mai multe ori. Există conexiuni lungi și parsing de pachete. Nu poți ști nimic despre protocolul HTTP, trebuie să-l înțelegi temeinic. Așa că am scris această serie pentru a împărtăși problemele și experiențele protocolului HTTP.
Protocolul HTTP are un antet și un corp pentru pachetele de cerere și răspuns, iar corpul este resursa pe care vrei să o obții, cum ar fi o pagină html, o imagine jpeg, iar antetul este folosit pentru a crea anumite convenții. De exemplu, clientul și serverul sunt de acord asupra unor formate de transmisie, iar clientul primește mai întâi antetul, cunoaște unele informații despre format, apoi începe să citească corpul.
Client: Accept-Encoding:gzip (comprimă-l pentru mine, folosesc trafic, descarcă-l mai întâi și apoi îl decomprimă încet)
Server 1: Conținut-Encoding: null (Fără antet Content-Encoding.) Eu nu dau compresie, CPU-ul nu este gratuit, îl vrei?)
Server 2: Conținut-Encoding:gzip (salvează traficul pentru tine, comprimă-l) Client: Conexiune: keep-alive (Frate mare, în sfârșit am construit o conexiune TCP, o vom folosi data viitoare)
Serverul 1: Conexiune: keep-alive (nu e ușor, continuă să folosești)
Server 2: Conexiune: închis (Cine continuă să-l folosească cu tine, TCP-ul nostru este de o singură dată și va trebui să ne reconectăm data viitoare când îl găsim) Protocolul HTTP nu are trei strângeri de mână, iar când un client solicită resurse de la server, partea de server va prevala. Există și unele antete care nu au un proces de negociere, dar serverul îi spune direct clientului ce să facă. De exemplu, lungimea conținutului de mai sus este ceea ce serverul îi spune clientului cât de mare este corpul. Dar! Chelnerul s-ar putea să nu-ți poată spune exact cât de mare este corpul dinainte. Serverul trebuie să scrie mai întâi antetul, apoi corpul; dacă vrei să scrii corpul în antet, trebuie să știi dimensiunea corpului dinainte. Dacă corpul este generat dinamic, serverul va termina și apoi va începe să scrie antetul, ceea ce necesită mult overhead suplimentar, astfel încât s-ar putea să nu existe o lungime de conținut în antet.
Deci, cum știe clientul dimensiunea corpului? Serverul îți spune în trei moduri.
1. Serverul știe deja dimensiunea resursei și îți spune prin antetul conținut-lungime.
Content-Length:1076(body的大小是1076B,你读取1076B就可以完成任务了)
Transfer-Encoding: null
2. Serverul nu poate cunoaște dimensiunea resursei dinainte sau nu este dispus să cheltuiască resurse pentru a calcula dimensiunea resursei dinainte, așa că va adăuga un antet mesajului de răspuns http numit Transfer-Encoding:chunked, ceea ce înseamnă transfer de blocuri. Fiecare bloc folosește un format fix, cu dimensiunea blocului în față, datele din spate și apoi ultimul bloc cu dimensiunea 0. Astfel, când clientul analizează, trebuie să acorde atenție eliminării unor câmpuri inutile.
Content-Length:null
Transfer-Encoding:chunked (接下来的body我要一块一块的传,每一块开始是这一块的大小,等我传到大小为0的块时,就没了)
3. Serverul nu cunoaște dimensiunea resursei și nu suportă modul de transmisie fragmentată, astfel încât nu există nici antetul conținut-lungime, nici antetul transfer-encoding. În acest moment, antetul returnat de server trebuie să fie aproape.
Content-Length:null
Transfer-Encoding:null
Connection:close(我不知道大小,我也用不了chunked,啥时候我关了tcp连接,就说明传输结束了)
|