2013-04-10 30 views
18

Sto implementando un proxy inverso per le richieste di routing a un server di backend.IIS come proxy inverso: compressione della risposta riscritta dal server di backend

Funzionalmente tutto funziona correttamente, tuttavia sono preoccupato che tutte le risposte dal server di back-end vengano trasferite al client (browser Web) senza compressione.

La messa a punto è il seguente:

  • server di back-end, non accessibile al pubblico, su un dominio interno. Host di un'applicazione Web su https://internal.app
  • Server Web anteriore con IIS 7.5, che ospita il sito Web pubblico principale e funge da proxy per il server di back-end. Il sito principale è https://site.com.

voglio percorso tutte le richieste a https://site.com/app/WHATEVER a https://internal.app/WHATEVER in un modo che sia trasparente per i clienti.

La mia attuale configurazione è basata su URL Rewrite 2.0 e sulle estensioni IIS di Routing Richiesta Applicazione. L'approccio generale si basa sulle linee guida dai seguenti articoli:

La sezione del web.config del site.com app:

<system.webServer> 
    <rewrite> 
     <rules> 
      <rule name="Route the requests for backend app" stopProcessing="true"> 
       <match url="^app/(.*)" /> 
       <conditions> 
        <add input="{CACHE_URL}" pattern="^(https?)://" /> 
       </conditions> 
       <action type="Rewrite" url="{C:1}://internal.app/{R:1}" /> 
       <serverVariables> 
        <set name="HTTP_ACCEPT_ENCODING" value="" /> 
       </serverVariables> 
      </rule> 
     </rules> 
     <outboundRules> 
      <rule name="RewriteBackendAbsoluteUrlsInResponse" preCondition="ResponseIsHtml1"> 
       <match filterByTags="A, Area, Base, Form, Frame, Head, IFrame, Img, Input, Link, Script" pattern="^http(s)?://internal.app(\:80)?/(.*)" /> 
       <action type="Rewrite" value="/app/{R:3}" /> 
      </rule> 
      <rule name="RewriteBackendAbsoluteUrlsInRedirects" preCondition="ResponseIsHtml1"> 
       <match serverVariable="RESPONSE_LOCATION" pattern="^http(s)?://internal.app(\:80)?/(.*)" /> 
       <action type="Rewrite" value="/app/{R:3}" /> 
      </rule> 
      <rule name="RewriteBackendRelativeUrlsInResponse" preCondition="ResponseIsHtml1"> 
       <match filterByTags="A, Area, Base, Form, Frame, Head, IFrame, Img, Input, Link, Script" pattern="^/(.*)" negate="false" /> 
       <conditions> 
        <add input="{URL}" pattern="^/app/.*" /> 
       </conditions> 
       <action type="Rewrite" value="/app/{R:1}" /> 
      </rule> 
      <rule name="RewriteBackendRelativeUrlsInRedirects" preCondition="ResponseIsHtml1"> 
       <match serverVariable="RESPONSE_LOCATION" pattern="^/(.*)" negate="false" /> 
       <conditions> 
        <add input="{URL}" pattern="^/app/.*" /> 
       </conditions> 
       <action type="Rewrite" value="/app/{R:1}" /> 
      </rule> 
      <preConditions> 
       <preCondition name="ResponseIsHtml1"> 
        <add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" /> 
       </preCondition> 
      </preConditions> 
     </outboundRules> 
    </rewrite> 
    <urlCompression dynamicCompressionBeforeCache="false" /> 
</system.webServer> 

Il problema è che non appena smetto di cancellare la variabile del server HTTP_ACCEPT_ENCODING, ogni richiesta corrisponde es la regola precedente termina con il seguente errore: HTTP Error 500.52 - URL Rewrite Module Error. Outbound rewrite rules cannot be applied when the content of the HTTP response is encoded ("gzip").

Sono a conoscenza di this thread e ho seguito tali istruzioni. Ho impostato dynamicCompressionBeforeCache="false" come si può vedere sopra, ho aggiunto la voce di registro necessaria e ho assicurato che i moduli sono nell'ordine corretto in IIS.

Tuttavia, questo sembra funzionare solo se la riscrittura si verifica all'interno di un'app Web. Se rimuovo le regole precedenti e aggiungo una semplice (e le rispettive regole in uscita) per riscrivere, ad es. /x/WHATEVER a solo /WHATEVER, tutto funziona perfettamente senza la necessità di cancellare HTTP_ACCEPT_ENCODING - la regola funziona e la compressione è abilitata per le richieste riscritte.

Ma non appena si aggiunge nuovamente la regola che riscrive la risposta a un'altra app Web e non si cancella l'intestazione HTTP_ACCEPT_ENCODING, viene visualizzato di nuovo lo stesso errore.

Da quello che ho capito, se la riscrittura coinvolge un'altra app Web, ci sono più limiti su cosa può essere fatto. Per esempio. Il rewriter di URL deve ricevere una risposta non compressa dal server di back-end per poterlo riscrivere utilizzando le regole in uscita. Immagino che azzerare HTTP_ACCEPT_ENCODING in questo scenario sia un must per questo.

Tuttavia, mi aspetto che, poiché il modulo di compressione è elencato in cima all'elenco dei moduli, la risposta riscritta finale dovrebbe essere compressa indipendentemente da dove ha avuto origine. Sembra che IIS crei alcune scorciatoie e restituisca la risposta al client ignorando il modulo di compressione.Oppure l'intestazione HTTP_ACCEPT_ENCODING viene rimossa abbastanza presto da disabilitare completamente la compressione (non solo nella comunicazione da server a server).

Quindi, alla fine, la mia domanda è: c'è un modo per comprimere quelle risposte?

risposta

24

L'ho capito da solo.

cosa deve essere fatto per farlo funzionare:

  • Accept-Encoding intestazione deve essere rimosso prima di routing la richiesta al server back-end, in modo che la risposta può essere riscritta utilizzando regole in uscita
  • l'intestazione deve essere ripristinato da un'ulteriore regola di accompagnamento in uscita, in modo che sia presente quando il modulo di compressione interviene prima che la risposta venga inviata al client

ho deciso di farlo in questo modo:

  • aggiungere una nuova variabile server alla regola di riscrittura per tenere lui intestazione originale inviato dal client:

    <set name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" value="{HTTP_ACCEPT_ENCODING}" /> 
    

    (l'ho messo prima della linea che cancella la variabile HTTP_ACCEPT_ENCODING)

  • aggiungere una nuova regola di uscita:

    <rule name="RestoreAcceptEncoding" preCondition="NeedsRestoringAcceptEncoding"> 
        <match serverVariable="HTTP_ACCEPT_ENCODING" pattern="^(.*)" /> 
        <action type="Rewrite" value="{HTTP_X_ORIGINAL_ACCEPT_ENCODING}" /> 
    </rule> 
    

    e una condizione di accompagnamento:

    <preCondition name="NeedsRestoringAcceptEncoding"> 
        <add input="{HTTP_X_ORIGINAL_ACCEPT_ENCODING}" pattern=".+" /> 
    </preCondition> 
    

funziona come un fascino finora.

+0

Grazie, ho bloggato sulla tua risposta qui: http://anjdreas.blogspot.no/2016/01/iis-aspnet- exposing-localhost-to-world.html – angularsen

+0

Contento di aver trovato questo utile e grazie per il collegamento di nuovo qui! –

+1

Hm, mi sento come se mi mancasse una parte della tua formula. Ho tutte queste cose a posto, eppure non vedo ancora alcuna compressione per i contenuti proxy. Qual è l'ordine dei tuoi moduli IIS? Importa dove 'HttpCacheModule' e' RewriteModule' sono in relazione a 'DynamicCompressionModule' e' StaticCompressionModule'? –

1

PS: la soluzione di seguito funziona solo se si ha il controllo sul proprio server delle applicazioni.

È fondamentalmente lasciare che il server Web esegua la compressione e lasciare che il server app svolga il compito più gravoso di ciò che l'app deve fare (senza compressione).

Se si disabilita la compressione sul server delle applicazioni, la risposta ricevuta dal server delle app non è compresso. Sul server Web, è necessario abilitare la compressione, in modo che il server Web rispetti l'intestazione HTTP "Accept-Encoding: gzip, deflate" mentre risponde al client (browser).

Questa configurazione scaricherà la CPU sul server delle app ma aumenterà il traffico di rete tra il server Web e il server delle applicazioni. Se ci si trova nella rete interna, non ha un impatto significativo sulle prestazioni.

+0

abbia funzionato per me, grazie. Ecco la pagina della documentazione per modificare queste impostazioni su IIS: https://www.iis.net/configreference/system.webserver/httpcompression –

1

Solo l'aggiunta di un tag "ServerVariables" nella regola di riscrittura ha fatto il trucco per me:

<rewrite> 
     <rules> 
      <rule name="ReverseProxyInboundRule1" stopProcessing="true"> 
       <match url="(.*)" /> 
       <action type="Rewrite" url="http://otherurl{R:1}" /> 

       <serverVariables> 
        <set name="HTTP_ACCEPT_ENCODING" value="" /> 
       </serverVariables> 
      </rule> 

     </rules> 
</rewrite> 
2

Per affrontare il problema del manifesto originale, mentre conservando gzip compressi risposte, bisogna semplicemente fare quanto segue :

  1. aggiornamento del registro di sistema sul server web pubblico di fronte in quanto tale:

    a. Per i siti Web a 64 bit, eseguire quanto segue in una console di comando con diritti di amministratore: reg add HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\InetStp\Rewrite /v LogRewrittenUrlEnabled /t REG_DWORD /d 0

    b. Per i siti web a 32 bit, eseguire il seguente in una console di comando con privilegi di amministratore: reg add HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432node\Microsoft\Inetstp\Rewrite /v LogRewrittenUrlEnabled /t REG_DWORD /d 0

  2. reimpostare IIS

  3. compressione statica disabilitare

    a. per raggiungere questo obiettivo, ho inserito il seguente My Web di configurazione: <urlCompression doStaticCompression="false" doDynamicCompression="true" dynamicCompressionBeforeCache="false" />

  4. nel nodo server in Gestione IIS, fare doppio clic sull'icona Modules, poi a destra, scatto "vista ordinò List" e verificare che la statica/I moduli di compressione dinamica sono verso l'alto e il modulo riscrittura URL è verso il fondo

noti prego

vedo molte risoluzioni a questo problema galleggianti intorno alla rete in cui l'intestazione richiesta HTTP_CONTENT_TYPE è essere eliminato come parte della regola di riscrittura degli URL (comprese le risposte in questa pagina). Si dovrebbe essere consapevoli che mentre questo risolve il problema originale dell'errore 500.52, la compressione gzip sulla risposta è RIMOSSO. Questo potrebbe essere il risultato desiderato, ma se è richiesta la compressione gzip, la soluzione sopra indicata farà il trucco