Riding internett bandwagon

Sende store sider med HTML er ikke lenger et problem nå som vi kan sende sidene komprimerte!
Etter to uker med non-stop programmering, er din webapplikasjon klar og testet. Alt er A-OK og gliser på dine kunder vender minne deg på en merkelig måte å "Jaws". Bortsett fra én ting. Noen i ryggen spør engstelig om noe kunne gjøres for å fremskynde at søkeresultatside som inneholder så mye tekst. I det øyeblikket du vet du burde ha tatt en full kopi av søknaden med deg i stedet for å demonstrere den over 33.6kb modemlinje på jobb.
Men alt er ikke tapt. Det er
måter å redusere mengden av data som du må sende til klienten, og jeg snakker ikke om å overføre mindre informasjon, men heller om å sende komprimerte data. Høres interessant ut? Les videre og lære.
Frivolous assumptionsSince denne artikkelen beskriver funksjonalitet og teknikker som vil legge til kompleksiteten av en web-applikasjon, er det forutsatt at du allerede vet hvordan å lage en web-applikasjon, spesielt en ISAPI dll, samt hvordan slike et program som fungerer. Som sådan vil jeg hoppe over noen detaljer, men trygg. - Jeg vil presentere deg med alle alternativene og kode som trengs spesielt for de teknikkene vi gjennomfører her
Med det i tankene, la oss gå klemme litt mer juice ut av good ol 'Internett-linjen.
Hvordan er den magiske gjort? Hvordan er dette mulig spør du kanskje? Du har sannsynligvis på en eller annen gang lastet ned en komprimert fil bare for å oppdage at din nettleser liksom tolket dataene som enten en nettside eller tekst og vises dette på skjermen i all sin prakt. Ikke et pent bilde for å si det mildt. Hvis du var å komprimere data før du sender den til klienten, ville det ikke ser like merkelig da? Ikke helt, bare sørg for at kunden vet at den skal håndtere det annerledes.
Hemmelighet er skjult både innenfor data klienten sender til webserveren og inne dataene webserveren svarer med. Det kalles Content Encoding. Kort sagt, kan du kode dataene dine programmet tilbake til klienten, og den eneste forholdsregler du må ta er å kontrollere at kunden vet hvordan de skal håndtere dataene i kode-format du velger. Dette i sin tur er enkelt siden klienten forteller deg hvilke formater den kan håndtere når den sender forespørselen til serveren.
Så hva det hele koker ned til, er at du må gjøre følgende hvis du ønsker å kode data tilbake til klienten:


    Sjekk om klient kan håndtere kodingstypen du vil bruke

    kode dataene i det valgte formatet

    Returner nylig kodede data og fortelle klienten hvilket format du har kodet det i
    Hvilket format bør jeg bruke? Vi er interessert i å komprimere data som vi kommer tilbake til klienten. Det er et kodingstypen spesielt for dette formålet, og det navnet er "tømming". Den komprimering algoritmen som brukes i deflate kodingstypen tilsvarer algoritmen at ZLIB komprimering bibliotek redskaper. Du kan lese mer om dette biblioteket her: http://www.cdrom.com/pub/infozip/zlib eller sjekk RFC som beskriver algoritmen og det er binært format her: http://www.funet.fi/pub/doc . /rfc/rfc1950.txt
    Selv om du kanskje tror at du allerede har filene som trengs for å bruke zlib komprimering bibliotek - du ikke! I alle fall ikke akkurat. Selv om Delphi installasjons CD kommer med en kopi av zlib komprimering bibliotek i form av ferdigbygd objekt-filer og noen importere filer, de skjuler detaljene vi trenger å bruke. Mer om det senere, men for nå la oss nok til å si vi trenger et bedre grensesnitt til biblioteket og for at jeg har valgt å forsyne deg med min egen ZLIB import enhet og en kobling til den nedlastbare forhåndskompilert dll: http: //www.winimage.com/zLibDll/.
    som for 'deflate' kodingstypen bare Microsoft Internet Explorer ser ut til å håndtere det og igjen bare de senere versjonene (versjon 4 og oppover håndterer det for sikkert, noe under som er usikker) . Dette er ikke et stort problem, men siden de andre nettlesere som Netscape, ikke si at de kan håndtere komprimeringskodingstypen. I dette tilfellet vår web-applikasjon rett og slett ikke ville komme tilbake med komprimerte data. Den eneste forskjellen vil være litt lengre tid å laste ned data til klienten. Dette er ikke verre enn det vi har i dag, så jeg tror vi kan leve med det.
    Ok, jeg fikk filene, hva nå? Nå er det på tide å komme ned til blodig detaljer. La oss få en god start ved å opprette en ny ISAPI prosjekt i Delphi 5 og se hvor det tar oss. Du bør legge den nedla import enheten til dette prosjektet også. Den dll du nettopp lastet ned kan settes enten i C: \\ WINNT \\ System32 katalogen (eller tilsvarende katalog) eller i samme katalog som din webapplikasjon
    Når du har opprettet det nye prosjektet la oss legge til noen handling til det, bokstavelig talt. . Legg en handling til web-modulen og opprette en tom hendelseshåndterer for det. Gjør handlingen standardhandlingen også siden dette er bare en demo program for å prøve ut vår nye måte å returnere data.
    Vi har nå en tom handling hendelseshåndterer så la? S legge til kode til det som vil gjøre det gjøre hva vi trenger. Jeg skal vise hele hendelsesbehandling først og så skal jeg gå gjennom detaljene
    prosedyre
    TWebModule1.WebModule1WebActionItem1Action (Sender: TObject, Request. TWebRequest; Response: TWebResponse; Var
    håndtert: Boolean); Var
    PlaintextStream: TStream; CompressedStream: TStream; begynne
    hvis plakater (ClientAcceptsDeflate (Request)) da
    begynne
    //1. Først må du opprette midlertidig strøm med dataene for å gå tilbake
    PlaintextStream: = TStringStream.Create ( 'Denne teksten er komprimert'); prøve
    //2. For det andre, å lage den midlertidige strøm for våre komprimerte data
    CompressedStream: = TMemoryStream.Create; prøve
    //3. Nå komprimere strømmen ...
    zLibCompressStream (PlaintextStream, CompressedStream);
    //... og returnere det
    CompressedStream. Beliggenhet: = 0; Response.ContentStream: = CompressedStream; bortsett
    FreeAndNil (CompressedStream); øke
    ; slutten
    ; //prøve unntak - unngå minnelekkasjer
    endelig
    //4. Til slutt rydde opp midlertidig objekt
    FreeAndNil (PlaintextStream); slutten
    ; //Prøve endelig - ødelegge klartekst stream objekt Response.ContentType: = 'text /plain'; Response.ContentEncoding: = 'deflate'; Response.StatusCode: = 200; Håndtert: = true; slutten
    //hvis kunden aksepterer komprimerte data
    ellers begynner
    Response.Content: = 'Ikke komprimert'; Response.ContentType: = 'text /plain'; Response.StatusCode: = 200; Håndtert: = true; slutten
    ; //hvis kunden ikke aksepterer komprimerte data
    slutten
    ; //prosedyre TWebModule1.WebModule1ActionItem1Action
    primære if-setning her avgjør hvorvidt klienten kan håndtere komprimerte data og sender enten komprimerte eller ukomprimerte data tilbake til klienten deretter. Den ukomprimerte data håndteres som du alltid har håndtert data i en webapplikasjon så vi vil ikke diskutere det videre. I stedet skal vi konsentrere oss om if-then del av if-setningen som håndterer komprimerte data. Du har sannsynligvis lagt merke til at vi bruker to nye prosedyrer /funksjoner her, nemlig ClientAcceptsDeflate og zLibCompressStream. Jeg vil gå gjennom de senere i denne artikkelen.
    Forutsatt at vi fikk en prosedyre som tar en bekk som input, komprimerer dataene denne strømmen holder og skriver de komprimerte data til en bekk som utgang, kan vi beskrive koden vist ovenfor som dette:

      Først opprette en midlertidig strøm som inneholder det vi ønsker å gå tilbake til klienten

      for det andre, komprimere disse dataene og sette komprimerte data til en ny strøm


      den nye strømmen, holder våre komprimerte data, vi bare gå tilbake til klienten

      til slutt, rydde vi opp våre midlertidige objekter i
      Du kan finne matchende interessante denne listen i de nummererte kommentarer av ovennevnte hendelsesbehandling. Det er ganske grunnleggende koden, og det burde være for siden vi har gjemt blodig detaljer i to funksjoner, som vi vil diskutere neste.
      En ting å merke seg er at når vi tildele ContentStream eiendommen av Response objektet til vår stream responsen-bject tar eierskap av bekken. Når responsen data har blitt sendt til kunden strømmen vil bli frigjort for oss, så vi må sørge for at vi ikke tilfeldigvis frigjøre det selv. Når det gjelder et unntak, men jeg gjør antagelsen om at oppdraget gikk haywire og dermed frigjøre strømmen før forplanter unntak høyere opp.
      Parlez-vous français? For å avgjøre om kunden vet hvordan de skal håndtere komprimerte data vi har å ta en titt på data den sender oss i første omgang. En typisk webforespørsel ser ut som dette (falske forespørsel, så detaljene er kanskje ikke 100% korrekt):
      GET /index.html HTTP /1.0 Godta-typer: * /* Accept-Encoding: gzip, deflate User-Agent : Mozilla 4.0 (Microsoft Internet Explorer 5.0 kompatibel, NT)
      det vi er interessert i er den linjen som går Accept-Encoding: gzip, deflate
      . Den forteller oss hva koding typer klienten er i stand til å akseptere, og i dette tilfellet kan det ta imot data som er kodet i gzip format samt deflate format. Sistnevnte er den vi trenger, så la oss se hvordan du kan få denne kunnskapen fra i vår web-applikasjon. Funksjonen ser slik ut:
      funksjon vi trenger å skrive ut:
      -funksjonen
      ClientAcceptsDeflate ( konst
      Request: TWebRequest): Boolean; Var
      EncodingTypes: string
      ; begynne
      //Get og reformatere liste over kodetypene fra forespørselen
      EncodingTypes: = Request.GetFieldByName ( 'HTTP_ACCEPT_ENCODING'); EncodingTypes: = store bokstaver (StringReplace (EncodingTypes, ',', '/', [rfReplaceAll])); EncodingTypes: = '/' + StringReplace (EncodingTypes, '', '', [rfReplaceAll]) + '/';
      //Returner flagget
      Resultat: = (Pos ( '/deflate /', EncodingTypes) > 0); slutten
      ; //funksjon ClientAcceptsDeflate
      Kort sagt reformatere jeg verdiene gzip, deflate
      inn /GZIP /deflatere /Hotell og deretter sjekke om strengen /deflate /
      er funnet i den. Hvis du er interessert i å vite hva andre felt kan bli funnet i anmodningen så foreslår jeg at du tar en titt på http://msdn.microsoft.com/library/psdk/iisref/isre504l.htm og bruke ALL_HTTP variabel for å kontrollere hva variabler klienten faktisk sender.
      naturelle, parlons! Etter at vi har funnet ut at klienten kan faktisk håndtere komprimerte data alt vi har igjen å gjøre er å produsere de komprimerte data og det er her den magi
      går.
      Som nevnt tidligere, vil vi bruke zlib kompresjon biblioteket for å gjøre den faktisk komprimere. Koden omfatter følgende trinn:

        Sett opp buffere for fôrings data til motoren samt godta komprimerte data fra det

        Initial komprimering motoren
        < li> Fôr ren tekst data inn i inngangsbuffer fra input stream

        Komprimer bufferen til utgangsbufferen

        Skriv data fra utgangsbufferen til utgangsstrømmen

        Gjenta trinn 3-5 til det ikke mer data i input stream og buffere er tømt

        Lukk komprimering motor
        la oss grave i detaljene, og se hva vi har å forholde seg til:
        prosedyre
        zLibCompressStream ( konst
        Source, Destination: TStream); Var
        z_s: z_stream; rc: Integer; //1. buffere for inngang og utgang
        SourceBuffer: rekke product: [0..BufferSize-1] av
        Byte; DestinationBuffer: rekke product: [0..BufferSize-1] av
        Byte; begynne
        //2. Klargjør ZLIB data posten
        z_init_zstream ( z_s); z_s.next_in: =SourceBuffer; z_s.next_out: =DestinationBuffer; z_s.avail_out: = buffer;
        //2. Initial komprimering motoren
        deflateInit2 (z_s, Z_BEST_COMPRESSION, Z_DEFLATED, -15, 9, Z_DEFAULT_STRATEGY);
        //Nå komprimere bekken
        prøve
        gjenta
        //3. Se om vi fikk mate mer data til komprimering motor
        hvis
        (z_s .avail_in = 0) og plakater (Source.Position < Source.Size) da
        begynner
        z_s.next_in: =SourceBuffer; z_s.avail_in: = Source.Read (SourceBuffer, Buffer); slutten
        ; //hvis inngangsdata helt utladet
        //4. komprimere data
        hvis plakater (z_s.avail_in = 0) da
        rc: = deflatere (z_s, Z_FINISH) annet
        rc: = deflatere (z_s, Z_STREAM_END);
        //5. Sjekk om vi fikk komprimert data til å skrive til destinasjonen
        hvis plakater (z_s.avail_out = 0) eller plakater (rc = Z_STREAM_END) da
        begynne
        Destination.WriteBuffer (DestinationBuffer, buffer - z_s. avail_out); z_s.avail_out: = buffer; z_s.next_out: =DestinationBuffer; slutten
        ; //hvis fikk data tilgjengelig for skriving
        //6. Gjenta inntil buffere oppbrukt til plakater (rc < > Z_OK) eller plakater ((rc = Z_STREAM_END) og plakater (z_s.avail_out = buffer) og plakater (z_s.avail_in = 0)); endelig
        //7. Rengjør opp motordata
        deflateEnd (z_s); slutten
        ; //prøve endelig - rydde opp etter at motoren
        slutten
        ; //prosedyre zLibCompressStream
        Som før, kan du matche poeng fra denne listen med de nummererte kommentarene ovenfor. Grunnen til at vi ikke kunne bruke ZLIB kode? S som følger med Delphi er at det skjuler deflateInit2 rutinen og de nødvendige parametere i gjennomføringen delen av enheten, samt ikke å utsette all nødvendig kode.
        For å produsere komprimerte data i måte at leseren kan håndtere, trenger vi å komprimere data uten header posten. Overskriften posten er en liten oversikt over informasjon som er skrevet til starten av komprimerte data og hjelper dekompresjon motor vet hvor mye data som følger. Vi kan velge å ikke skrive denne overskriften posten ved å sende en negativ verdi for wBitSize parameter til deflateInit2 prosedyren. Siden deflate standard som nettlesere holder seg til, ikke forvent heller ikke vet hvordan man skal håndtere denne overskriften har vi for å filtrere det ut. Siden vi ikke kunne kalle deflateInit2 direkte med ZLIB koden som fulgte med Delphi vi måtte ty til en full dll kopi av komprimering bibliotek.
        Kompresjon motoren er i stand til å komprimere data fra inngangsbuffer og skrive det til utgangen buffer. Når utgangen bufferen er full, må vår kode for å skylle denne bufferen og skrive data i den til målet, i vårt tilfelle en bekk. Når det har klart å komprimere alle data fra inngangsbufferne, trenger vår kode for å fylle opp bufferen igjen med så mye data som mulig. Kompresjonen Motoren tar seg av resten.
        Testing itAfter kompilere din webapplikasjon (se nederst i artikkelen for en kopi av eksempelprosjektet gjennomføres i denne artikkelen) bør du ideelt teste det med både en nettleser som håndterer komprimerte data og med en som ikke gjør det. Du kan bruke Internet Explorer 4/5 som tidligere og Netscape 4.06 som sistnevnte. Nettleseren som håndterer komprimering skal vise teksten "Denne teksten er komprimert" og den andre "Ikke komprimert 'for verifisering.
        Gjennomsnittlig kompresjonsforhold på tekstbasert innhold er ca 5-6 ganger (15-20% av opprinnelig størrelse) slik at effekten skal være lett å få øye på store nettsider.
        pakke det Upwell, det er det. Med koden og kunnskapen som finnes i denne artikkelen bør du nå være i stand til å håndtere komprimerte data fra din webapplikasjon. Selv om vi laget en ISAPI dll i denne artikkelen, bør teori og koden forblir den samme også for CGI og NSAPI applikasjoner.
        Jeg har tatt meg den frihet å opprette en enhet med de to funksjonene som er beskrevet ovenfor, samt en kopi av eksempel produseres i denne artikkelen. Du kan laste ned filer fra listen nedenfor. Hvis det er noen forslag eller ting du ønsker å kommentere jeg kan nås på [email protected]
        filer for nedlasting.
      1. ZLIB dll (fra forfattere nettsted)

        import enhet for zLib.dll

        Eksempel prosjektet (inkludert enhet med to funksjoner samt import enhet)

        Kun enheten med de to funksjonene vi skrev
        det er et par av etterbehandling notater å huske på:

        kompresjons~~POS=TRUNC motoren ikke fastslå om dataene gir seg lett til kompresjon eller ikke før den starter tygge på den. Dette betyr at det er mulig å mate data ved hjelp av det som ikke kan komprimeres, og kan til og med øke i størrelse i stedet. For tekst og nettsider er dette ikke et problem men, men jeg ville gjøre noen tester før fôring JPEG eller GIF-filer inn i den.
      2. Kompresjons gjøres på serversiden før den sendes så hvis klienten er prøver å laste ned en veldig stor nettside deretter hovedsak webapplikasjonen laster hele siden inn i minnet, komprimerer den og sender den. Hvis minneforbruket på serversiden er et problem så ville jeg foreslå å gjennomføre komprimering kode i en TStream-avledet klasse som komprimerer når du leser fra den. På den måten komprimering gjøres on-the-fly som dataene sendes og kan mates direkte av disken gjennom komprimering bibliotek til klienten. Klasser for å gjøre dette er tilgjengelig på hjemmesiden min i pakken heter StreamFilter.