web-dev-qa-db-fra.com

IIS en tant que proxy inverse - compression de réponse réécriture de Backend Server

Je suis en train de mettre en œuvre un proxy inverse pour les demandes de routage à un serveur de backend.

Fonctionnellement, tout fonctionne correctement, mais je suis préoccupé par le fait que toutes les réponses du serveur Backend sont transférées sur le client (navigateur Web) sans compression.

La configuration est la suivante:

  • Server Backend, non accessible pour le public, sur un domaine interne. Les hôtes une application web sur https://internal.app
  • Serveur web avant avec IIS 7.5, qui héberge le principal site Web public et d'agir en tant que proxy pour le serveur principal. Le site principal est à https://site.com.

Je veux d'acheminer toutes les demandes de https://site.com/app/WHATEVER à https://internal.app/WHATEVER d'une manière qui est transparente pour les clients.

Ma configuration actuelle est basée sur l'URL Rewrite 2.0 et demande d'application de routage IIS extensions. L'approche générale est fondée sur les lignes directrices des articles suivants:

La section pertinente de web.config de l'application site.com:

<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>

Le problème est que, dès que j'arrête la compensation variable serveur HTTP_ACCEPT_ENCODING, chaque requête qui correspond à la fin de la règle ci-dessus avec l'erreur suivante: HTTP Error 500.52 - URL Rewrite Module Error. Outbound rewrite rules cannot be applied when the content of the HTTP response is encoded ("gzip").

Je suis au courant de ce fil et j'ai suivi ces instructions. J'ai mis dynamicCompressionBeforeCache="false" comme on peut le voir ci-dessus, j'ai ajouté l'entrée de Registre nécessaire et je l'ai assuré que les modules sont dans l'ordre correct dans IIS.

Cependant, cela ne semble fonctionner que si la réécriture se produit dans une application Web. Si je supprimais les règles ci-dessus et ajoute une simple (et des règles sortantes respectives) pour réécrire par ex. /x/WHATEVER juste /WHATEVER, tout fonctionne parfaitement sans besoin de HTTP_ACCEPT_ENCODING clair - les travaux de règle et la compression est activée pour les demandes réécrites.

Mais dès que j'ajouter à nouveau ma règle qui réécrit la réponse à une application Web différente, et je ne suis pas clair l'en-tête de HTTP_ACCEPT_ENCODING, la même erreur apparaît à nouveau.

D'après ce que je comprends, si la réécriture implique une autre application Web, il y a plus de contrainte sur ce qui peut être fait. Par exemple. L'URL Rewriter doit recevoir une réponse non compressée du serveur Backend afin de pouvoir la réécrire à l'aide des règles sortantes. Je suppose que la compensation HTTP_ACCEPT_ENCODING dans ce scénario est un must à cause de cela.

Cependant, je m'attendrais à ce que le module de compression soit répertorié en plus de la liste des modules, la réponse finale de réécriture doit être comprimée, peu importe son origine. Il semble IIS fait des raccourcis et renvoie la réponse au client sans passer par le module de compression. Ou l'en-tête HTTP_ACCEPT_ENCODING est retiré assez rapidement pour désactiver complètement la compression (non seulement en communication de serveur à serveur).

Enfin, ma question est la suivante: y a-t-il un moyen de comprimer ces réponses?

20

Je me suis compris moi-même.

Ce qui doit être fait pour le faire fonctionner:

  • Accept-Encoding L'en-tête doit être supprimé avant de rouler la demande sur le serveur Backend, de sorte que la réponse puisse être réécrite en utilisant des règles sortantes.
  • L'en-tête doit être restauré par une règle sortante accompagnante supplémentaire, de sorte qu'elle est présente lorsque le module de compression commence avant que la réponse soit envoyée au client

J'ai décidé de le faire comme ça:

  • ajoutez une nouvelle variable de serveur à la règle de réécriture pour maintenir l'en-tête d'origine envoyé par le client:

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

    (Je le mets avant la ligne qui efface le HTTP_ACCEPT_ENCODING variable)

  • ajouter une nouvelle règle sortante:

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

    et une condition préalable d'accompagnement:

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

Fonctionne comme un charme jusqu'à présent.

25

Pour résoudre le problème de l'affiche original tandis conservant toujours des réponses comprimées GZIP, il suffit de faire ce qui suit:

  1. mettez à jour le registre de votre serveur Web confronté en tant que tel:

    une. Pour les sites Web 64 bits, exécutez ce qui suit dans une console de commande avec les droits de l'administrateur: reg add HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\InetStp\Rewrite /v LogRewrittenUrlEnabled /t REG_DWORD /d 0

    b. Pour les sites Web 32 bits, exécutez les éléments suivants dans une console de commande avec les droits de l'administrateur: reg add HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432node\Microsoft\Inetstp\Rewrite /v LogRewrittenUrlEnabled /t REG_DWORD /d 0

  2. réinitialiser IIS

  3. désactiver la compression statique

    une. Pour y accomplir, j'ai inséré le suivant ma configuration Web: <urlCompression doStaticCompression="false" doDynamicCompression="true" dynamicCompressionBeforeCache="false" />

  4. dans le noeud de serveur In IIS Manager, double-cliquez sur l'icône Modules, puis sur la droite, cliquez sur "Afficher la liste des commandes" et vérifiez que vos modules de compression statiques/dynamiques sont vers le haut et le module de réécriture d'URL est vers le bas

Veuillez noter

Je vois beaucoup de résolutions à ce sujet flottant autour du net où l'en-tête de demande http_content_type est édité dans le cadre de la règle de réécriture URL (y compris les réponses de cette page). Il faut savoir que, même si cela résolve le problème d'origine de l'erreur 500.52, la compression GZIP sur la réponse est RETIRÉ . Cela peut être le résultat souhaité, mais si la compression GZIP requise, la solution ci-dessus fera le tour

2
Scot

PS: La solution ci-dessous ne fonctionne que si vous souhaitez contrôler votre serveur d'applications.

Il s'agit essentiellement de laisser le serveur Web effectuer la compression et de laisser le serveur d'applications à faire le poids lourd de ce que l'application est censée faire (sans compression).

Si vous désactivez la compression sur le serveur d'applications, la réponse que vous obtenez auprès de l'App Server est décompressée. Sur le serveur Web, vous devez activer la compression, de sorte que Web Server honorera l'en-tête HTTP "Accepter-coding: gzip, déflate" tout en répondant au client (navigateur).

Cette configuration déchargea la CPU sur le serveur d'applications mais augmentera le trafic réseau entre votre serveur Web et votre serveur d'applications. Si vous êtes sur le réseau interne, il n'a pas d'impact de beaucoup de performances.

1
Gunawan Deng