Comment configurer IIS pour la réécriture d'URL d'une application AngularJS en mode HTML5?

140

J'ai le projet d'amorçage AngularJS et j'ai ajouté

$locationProvider.html5Mode(true).hashPrefix('!');

dans le fichier app.js. Je souhaite configurer IIS 7 pour acheminer toutes les demandes vers

http://localhost/app/index.html

pour que cela fonctionne pour moi. Comment puis-je faire cela?

Mettre à jour:

Je viens de découvrir, télécharger et installer le module de réécriture d'URL IIS , en espérant que cela rendra facile et évident d'atteindre mon objectif.

Mise à jour 2 :

Je suppose que cela résume ce que j'essaie de réaliser (tiré de la documentation AngularJS Developer ):

L'utilisation de ce mode nécessite une réécriture d'URL côté serveur, en gros vous devez réécrire tous vos liens vers le point d'entrée de votre application (par exemple index.html)

Mise à jour 3:

Je travaille toujours là-dessus et je me rends compte que je ne dois PAS rediriger (avoir des règles qui réécrivent) certaines URL telles que

http://localhost/app/lib/angular/angular.js
http://localhost/app/partials/partial1.html

donc tout ce qui se trouve dans les répertoires css, js, lib ou partials n'est pas redirigé. Tout le reste devra être redirigé vers app / index.html

Quelqu'un sait comment y parvenir facilement sans avoir à ajouter une règle pour chaque fichier?

Mise à jour 4:

J'ai 2 règles entrantes définies dans le module de réécriture d'URL IIS. La première règle est:

Règle entrante de réécriture d'URL IIS 1

La deuxième règle est:

Règle entrante de réécriture d'URL IIS 2

Maintenant, lorsque je navigue vers localhost / app / view1, il charge la page, mais les fichiers de support (ceux des répertoires css, js, lib et partials) sont également réécrits sur la page app / index.html - donc tout est à venir retour en tant que page index.html quelle que soit l'URL utilisée. Je suppose que cela signifie que ma première règle, qui est censée empêcher ces URL d'être traitées par la deuxième règle, ne fonctionne pas… aucune idée? ...n'importe qui? ...Je me sens si seul... :-(

doyen
la source
Merci pour cela! Très utile!
Ash Clarke
la deuxième règle est essentielle: vous devez vous assurer qu'il est acheminé vers app/index.htmlet ne app/ pas déclencher explicitement la page qui sert AngularJS. J'ai perdu 2 heures de ma vie avant de le découvrir. :-)
Dexter Legaspi
Une autre façon d'utiliser ASP.NET MVC et d'ajouter à RouteConfig.cs: routes.MapRoute (nom: "Default", url: "{* any}", par défaut: new {controller = "Home", action = "Index", }); et votre index HomeController renvoie juste File ("~ / index-anyhinghere.html", "text / html"); Ensuite, votre application devient indépendante d'IIS
Toolkit
J'ai dû installer "le module de réécriture d'URL de 'Web Installer'". Si le module de réécriture d'url n'est pas là, alors lors du rechargement, la réécriture ne fonctionnera pas. INSTALLER le module de réécriture d'URL. :)
Bimal Das

Réponses:

289

J'écris une règle dans web.config après avoir $locationProvider.html5Mode(true)été défini app.js.

Hope, aide quelqu'un.

  <system.webServer>
    <rewrite>
      <rules>
        <rule name="AngularJS Routes" stopProcessing="true">
          <match url=".*" />
          <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
            <add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
          </conditions>
          <action type="Rewrite" url="/" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>

Dans mon index.html j'ai ajouté ceci à <head>

<base href="/">

N'oubliez pas d'installer IIS URL Rewrite sur le serveur.

De plus, si vous utilisez l'API Web et IIS, cela fonctionnera si votre API est à en www.yourdomain.com/apiraison de la troisième entrée (troisième ligne de condition).

Yagiz Ozturk
la source
2
Cela a été très utile et je l'ai trouvé le plus complet. Merci!
Mario
2
heureux que cela aide @Mario
Yagiz Ozturk
5
PARFAIT! Celui-ci a été un problème difficile pour moi, j'ai passé des heures à y travailler. Merci! CONSEIL À TOUT LE MONDE: J'ai ajouté index.html à <action type = "Rewrite" url "/index.html" /> Puis sur mon index.html (fichier de répertoire racine pour Angular SPA, le <base href = "/ index .html "/> Quand j'ai copié le code ci-dessus, il ne correspondait pas à mon <base href /> donc cela ne fonctionnait pas correctement. Énormes accessoires pour le modèle" / (api) "aussi, je n'arrêtais pas de trébucher sur cette partie.
Brad Martin
et si j'héberge sur des sites Web Azure?
Boîte à outils
7
C'est une blague que nous devons sauter à travers ces cerceaux pour le routage angulaire. Cela tue le routage angulaire pour moi. Quel bordel.
user441521
38

Les règles entrantes IIS comme indiqué dans la question fonctionnent. J'ai dû vider le cache du navigateur et ajouter la ligne suivante en haut de ma <head>section de la page index.html:

<base href="/myApplication/app/" />

C'est parce que j'ai plus d'une application dans localhost et que les demandes à d'autres partiels ont donc été prises au localhost/app/view1lieu delocalhost/myApplication/app/view1

Espérons que cela aide quelqu'un!

doyen
la source
1
Je n'avais pas besoin de cela, mais les modifications apportées aux questions étaient super. Merci!
Ash Clarke
2
Cela peut également être utile. A travaillé pour moi lors du rechargement de la page. Sans aucune règle particulière pour chaque fichier: coderwall.com/p/mycbiq
Par G
comme @ ash-clarke l'a dit, ce n'est pas nécessaire mais c'est quand même une bonne pratique car cela permet aux liens sur la page d'être indépendants du "sous-répertoire" auquel il appartient.
Dexter Legaspi
@PerG J'ai rencontré la solution ci-dessus fonctionnant mais pas lors du rechargement, voici mon code: stackoverflow.com/questions/25644287/iis-url-rewrite-rules Des idées?
amcdnl
Je ne sais pas ou j'ai essayé de filtrer certains appels. Un moyen de contourner serait d'avoir une API sur un autre domaine, etc. Mais ce n'est peut-être pas une solution pour u. Mais vous pouvez continuer à demander dans mon lien ci-dessus. Et peut-être que l'auteur peut vous répondre?
Per G
11

Dans mon cas, j'ai continué à obtenir un 403.14 après avoir configuré les règles de réécriture correctes. Il s'avère que j'avais un répertoire qui portait le même nom que l'une de mes routes URL. Une fois que j'ai supprimé la règle de réécriture IsDirectory, mes itinéraires fonctionnaient correctement. Existe-t-il un cas où la suppression de la négation du répertoire peut causer des problèmes? Je ne peux penser à aucun dans mon cas. Le seul cas auquel je puisse penser est si vous pouvez parcourir un répertoire avec votre application.

<rule name="fixhtml5mode" stopProcessing="true">
  <match url=".*"/>
  <conditions logicalGrouping="MatchAll">
    <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
  </conditions>
  <action type="Rewrite" url="/" />
</rule>
Josh C
la source
10

Le problème avec seulement ces deux conditions:

  <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
  <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />

est qu'ils ne fonctionnent que tant que le {REQUEST_FILENAME} existe physiquement sur le disque . Cela signifie qu'il peut y avoir des scénarios où une requête pour une vue partielle incorrectement nommée renverrait la page racine au lieu d'un 404, ce qui entraînerait le chargement double de angular (et dans certains scénarios, cela peut provoquer une boucle infinie désagréable).

Ainsi, certaines règles de «secours» sûres seraient recommandées pour éviter ces problèmes difficiles à résoudre:

  <add input="{REQUEST_FILENAME}" pattern="(.*?)\.html$" negate="true" />
  <add input="{REQUEST_FILENAME}" pattern="(.*?)\.js$" negate="true" />
  <add input="{REQUEST_FILENAME}" pattern="(.*?)\.css$" negate="true" />

ou une condition qui correspond à n'importe quelle fin de fichier :

<conditions>
  <!-- ... -->
  <add input="{REQUEST_FILENAME}" pattern=".*\.[\d\w]+$" negate="true" />
</conditions>
Ciprian Teiosanu
la source
1
Avec tout cela en place, mon site se charge très bien, mais si je suis sur un chemin le long de la route, j'ai des problèmes. Ainsi, si le chemin dans mon navigateur est: 10.34.34.46/jbvdev/documents/BC498484 Au départ, il apparaît bien, mais si je clique sur Actualiser , tout se brise car il commence à rechercher le css et js à 10.34.34.46/jbvdev/documents / css ou 10.34.34.46/jbvdev/documents/js Quelqu'un sait-il comment résoudre celui-ci?
Michael Mahony
1

Le moyen le plus simple que j'ai trouvé est simplement de rediriger les demandes qui déclenchent 404 vers le client. Cela se fait en ajoutant un hashtag même lorsqu'il $locationProvider.html5Mode(true)est défini.

Cette astuce fonctionne pour les environnements avec plus d'applications Web sur le même site Web et nécessitant des contraintes d'intégrité d'URL (authentification externe EG). Voici comment faire étape par étape

index.html

Réglez l' <base>élément correctement

<base href="@(Request.ApplicationPath + "/")">

web.config

Redirigez d'abord 404 vers une page personnalisée, par exemple "Accueil / Erreur"

<system.web>
    <customErrors mode="On">
        <error statusCode="404" redirect="~/Home/Error" />
    </customErrors>
</system.web>

Contrôleur domestique

Implémentez une ActionResultentrée simple à «traduire» dans une route côté client.

public ActionResult Error(string aspxerrorpath) {
    return this.Redirect("~/#/" + aspxerrorpath);
}

C'est la manière la plus simple.


Il est possible (conseillé?) D'améliorer la fonction d'erreur avec une logique améliorée pour rediriger 404 vers le client uniquement lorsque l'URL est valide et laisser le 404 se déclencher normalement lorsque rien ne sera trouvé sur le client. Disons que vous avez ces routes angulaires

.when("/", {
    templateUrl: "Base/Home",
    controller: "controllerHome"
})
.when("/New", {
    templateUrl: "Base/New",
    controller: "controllerNew"
})
.when("/Show/:title", {
    templateUrl: "Base/Show",
    controller: "controllerShow"
})

Il est judicieux de rediriger l'URL vers le client uniquement lorsqu'elle commence par "/ Nouveau" ou "/ Afficher /"

public ActionResult Error(string aspxerrorpath) {
    // get clientside route path
    string clientPath = aspxerrorpath.Substring(Request.ApplicationPath.Length);

    // create a set of valid clientside path
    string[] validPaths = { "/New", "/Show/" };

    // check if clientPath is valid and redirect properly
    foreach (string validPath in validPaths) {
        if (clientPath.StartsWith(validPath)) {
            return this.Redirect("~/#/" + clientPath);
        }
    }

    return new HttpNotFoundResult();
}

Ceci n'est qu'un exemple de logique améliorée, bien sûr, chaque application Web a des besoins différents

Naigel
la source
1

J'ai essayé de déployer une simple application Angular 7 sur une application Web Azure. Tout a bien fonctionné, jusqu'au moment où vous avez actualisé la page. Ce faisant, me présentait un contenu déplacé par erreur 500. J'ai lu à la fois sur la documentation Angular et dans quelques bons forums, que j'ai besoin d'ajouter un fichier web.config à ma solution déployée et de m'assurer que la règle de réécriture revient au fichier index.html. Après des heures de frustration et de tests d'essais et d'erreurs, j'ai trouvé que l'erreur était assez simple: ajouter une balise autour du balisage de mon fichier.

Kelson Martins
la source
1

J'ai eu un problème similaire avec Angular et IIS lançant un code d'état 404 sur l'actualisation manuelle et j'ai essayé la solution la plus votée, mais cela n'a pas fonctionné pour moi. Également essayé un tas d'autres solutions devant faire face à WebDAV et changer de gestionnaire et aucune n'a fonctionné.

Heureusement, j'ai trouvé cette solution et cela a fonctionné (j'ai retiré des pièces dont je n'avais pas besoin). Donc, si aucune des solutions ci-dessus ne fonctionne pour vous ou même avant de les essayer, essayez ceci et voyez si cela résout votre problème de déploiement angulaire sur iis.

Ajoutez l'extrait de code à votre webconfig dans le répertoire racine de votre site. D'après ce que je comprends, il supprime le code d'état 404 de tout héritage (applicationhost.config, machine.config), puis crée un code d'état 404 au niveau du site et redirige vers la page d'accueil en tant que page 404 personnalisée.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <httpErrors errorMode="Custom">
      <remove statusCode="404"/>
      <error statusCode="404" path="/index.html" responseMode="ExecuteURL"/>
    </httpErrors>
  </system.webServer>
</configuration>
Melvin Gaye
la source