Wie konfiguriere ich IIS für das URL-Umschreiben einer AngularJS-Anwendung im HTML5-Modus?

140

Ich habe das AngularJS-Seed-Projekt und habe hinzugefügt

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

in die Datei app.js. Ich möchte IIS 7 so konfigurieren, dass alle Anforderungen an weitergeleitet werden

http://localhost/app/index.html

damit das bei mir funktioniert. Wie mache ich das?

Aktualisieren:

Ich habe gerade das IIS URL Rewrite-Modul entdeckt, heruntergeladen und installiert , in der Hoffnung, dass dies das Erreichen meines Ziels einfach und offensichtlich macht.

Update 2 :

Ich denke, dies fasst zusammen, was ich erreichen möchte (entnommen aus der AngularJS Developer-Dokumentation ):

Wenn Sie diesen Modus verwenden, müssen Sie die URL auf der Serverseite neu schreiben. Grundsätzlich müssen Sie alle Links zum Einstiegspunkt Ihrer Anwendung (z. B. index.html) neu schreiben.

Update 3:

Ich arbeite immer noch daran und mir ist klar, dass ich bestimmte URLs wie z. B. NICHT umleiten muss (Regeln haben, die neu schreiben)

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

Daher wird alles, was sich in den Verzeichnissen css, js, lib oder partials befindet, nicht umgeleitet. Alles andere muss nach app / index.html umgeleitet werden

Weiß jemand, wie man dies einfach erreicht, ohne für jede einzelne Datei eine Regel hinzufügen zu müssen?

Update 4:

Ich habe 2 eingehende Regeln im IIS URL Rewrite-Modul definiert. Die erste Regel lautet:

Eingehende IIS-URL neu schreiben Regel 1

Die zweite Regel lautet:

Eingehende IIS-URL neu schreiben Regel 2

Wenn ich jetzt zu localhost / app / view1 navigiere, wird die Seite geladen, aber die unterstützenden Dateien (die in den Verzeichnissen css, js, lib und partials) werden auch in die Seite app / index.html umgeschrieben - also kommt alles zurück als index.html Seite, egal welche URL verwendet wird. Ich denke, dies bedeutet, dass meine erste Regel, die verhindern soll, dass diese URLs von der zweiten Regel verarbeitet werden, nicht funktioniert. Irgendwelche Ideen? ...jemand? ... ich fühle mich so alleine ... :-(

Dean
quelle
Danke dafür! Sehr hilfreich!
Ash Clarke
Die zweite Regel ist von entscheidender Bedeutung: Sie müssen sicherstellen, dass das Routing zu app/index.htmlund nicht app/ explizit die Seite auslöst, auf der AngularJS bereitgestellt wird. Ich habe 2 Stunden meines Lebens verloren, bevor ich es herausgefunden habe. :-)
Dexter Legaspi
Eine andere Möglichkeit, ASP.NET MVC zu verwenden und zu RouteConfig.cs hinzuzufügen: route.MapRoute (Name: "Standard", URL: "{* irgendetwas}", Standard: neu {controller = "Home", action = "Index", }); und Ihr HomeController-Index gibt nur Datei zurück ("~ / index-anyhinghere.html", "text / html"); Dann wird Ihre App IIS-unabhängig
Toolkit
Ich musste "URL rewrite module from 'Web Installer'" installieren. Wenn das URL-Rewrite-Modul nicht vorhanden ist, funktioniert das Rewrite beim Neuladen nicht. INSTALLIEREN Sie das URL-Umschreibemodul. :)
Bimal Das

Antworten:

289

Ich schreibe eine Regel in web.config, nachdem sie $locationProvider.html5Mode(true)eingestellt wurde app.js.

Hoffe, hilft jemandem aus.

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

In meiner index.html habe ich dies hinzugefügt <head>

<base href="/">

Vergessen Sie nicht, IIS URL Rewrite auf dem Server zu installieren .

Auch wenn Sie Web-API und IIS verwenden, funktioniert dies, wenn sich Ihre API www.yourdomain.com/apiaufgrund der dritten Eingabe (dritte Bedingungszeile) befindet.

Yagiz Ozturk
quelle
2
Dies war sehr nützlich und ich fand es am vollständigsten. Vielen Dank!
Mario
2
froh, dass es hilft @Mario
Yagiz Ozturk
5
PERFEKT! Dieser war ein schwieriges Thema für mich, ich habe stundenlang daran gearbeitet. Vielen Dank! HINWEIS FÜR JEDEN ANDEREN: Ich habe index.html zur <action type = "Rewrite" url "/index.html" /> hinzugefügt. Dann in meiner index.html (Stammverzeichnisdatei für Angular SPA, <base href = "/ index .html "/> Als ich den obigen Code kopierte, stimmte er nicht mit meiner <base href /> überein, so dass er nicht richtig funktionierte. Riesige Requisiten für das" / (api) "- Muster auch, ich stolperte immer wieder über diesen Teil.
Brad Martin
Was passiert, wenn ich auf Azure-Websites hoste?
Toolkit
7
Es ist ein Witz, dass wir für Angular Routing durch diese Reifen springen müssen. Dies tötet das eckige Routing für mich. Was für ein Chaos.
user441521
38

Die in der Frage gezeigten eingehenden IIS-Regeln funktionieren. Ich musste den Browser-Cache leeren und die folgende Zeile oben in meinem <head>Abschnitt der index.html-Seite hinzufügen :

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

Das ist , weil ich mehr als eine Anwendung in localhost haben und so Anfragen an andere partials wurden genommen werden localhost/app/view1stattlocalhost/myApplication/app/view1

Hoffentlich hilft das jemandem!

Dean
quelle
1
Ich brauchte das nicht, aber die Fragenbearbeitungen waren großartig. Vielen Dank!
Ash Clarke
2
Auch das kann nützlich sein. Arbeitete für mich beim Neuladen der Seite. Ohne spezielle Regeln für jede Datei: coderwall.com/p/mycbiq
Per G
Wie @ ash-clarke sagte, ist es nicht notwendig, aber es ist trotzdem eine gute Praxis, da die Links auf der Seite unabhängig davon sein können, zu welchem ​​"Unterverzeichnis" es gehört.
Dexter Legaspi
@PerG Ich bin auf die obige Lösung gestoßen, die funktioniert, aber nicht beim Neuladen. Hier ist mein Code: stackoverflow.com/questions/25644287/iis-url-rewrite-rules Irgendwelche Ideen?
Amcdnl
Ich weiß es nicht oder habe nicht versucht, bestimmte Anrufe herauszufiltern. Ein Ausweg wäre, API auf einer anderen Domain usw. zu haben. Aber vielleicht ist dies keine Lösung für Sie. Aber du kannst weiterhin in meinem Link oben fragen. Und vielleicht kann der Autor Ihnen antworten?
Per G
11

In meinem Fall bekam ich immer wieder eine 403.14, nachdem ich die richtigen Umschreiberegeln eingerichtet hatte. Es stellte sich heraus, dass ich ein Verzeichnis hatte, das den gleichen Namen wie eine meiner URL-Routen hatte. Nachdem ich die IsDirectory-Umschreiberegel entfernt hatte, funktionierten meine Routen ordnungsgemäß. Gibt es einen Fall, in dem das Entfernen der Verzeichnisnegation Probleme verursachen kann? In meinem Fall fällt mir nichts ein. Der einzige Fall, an den ich denken kann, ist, wenn Sie mit Ihrer App ein Verzeichnis durchsuchen können.

<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.
quelle
10

Das Problem, nur diese beiden Bedingungen zu haben:

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

ist, dass sie nur funktionieren, solange die {REQUEST_FILENAME} physisch auf der Festplatte vorhanden sind . Dies bedeutet, dass es Szenarien geben kann, in denen eine Anforderung für eine falsch benannte Teilansicht die Stammseite anstelle einer 404 zurückgibt, was dazu führt, dass Angular zweimal geladen wird (und in bestimmten Szenarien eine unangenehme Endlosschleife verursachen kann).

Daher werden einige sichere "Fallback" -Regeln empfohlen, um diese schwer zu behebenden Probleme zu vermeiden:

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

oder eine Bedingung, die mit einem beliebigen Dateiende übereinstimmt :

<conditions>
  <!-- ... -->
  <add input="{REQUEST_FILENAME}" pattern=".*\.[\d\w]+$" negate="true" />
</conditions>
Ciprian Teiosanu
quelle
1
Wenn all dies vorhanden ist, wird meine Website einwandfrei geladen, aber wenn ich mich auf einem Pfad entlang der Route befinde, habe ich Probleme. Wenn der Pfad in meinem Browser also lautet: 10.34.34.46/jbvdev/documents/BC498484 Anfangs wird er gut angezeigt , aber wenn ich auf Aktualisieren drücke, bricht alles ab, weil er unter 10.34.34.46/jbvdev/documents nach CSS und JS sucht / css oder 10.34.34.46/jbvdev/documents/js Weiß jemand, wie man dieses Problem löst?
Michael Mahony
1

Der einfachste Weg, den ich gefunden habe, besteht darin, die Anforderungen, die 404 auslösen, an den Client umzuleiten. Dies erfolgt durch Hinzufügen eines Hashtags, auch wenn dieses festgelegt $locationProvider.html5Mode(true)ist.

Dieser Trick funktioniert in Umgebungen mit mehr Webanwendungen auf derselben Website, für die Einschränkungen der URL-Integrität erforderlich sind (z. B. externe Authentifizierung). Hier erfahren Sie Schritt für Schritt, wie es geht

index.html

Stellen Sie das <base>Element richtig ein

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

web.config

Leiten Sie zuerst 404 auf eine benutzerdefinierte Seite um, z. B. "Home / Error".

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

Home-Controller

Implementieren Sie eine einfach ActionResultzu übersetzende Eingabe in eine clientseitige Route.

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

Dies ist der einfachste Weg.


Es ist möglich (ratsam?), Die Fehlerfunktion mit einer verbesserten Logik zu erweitern, um 404 nur dann zum Client umzuleiten, wenn die URL gültig ist, und den 404 normal auslösen zu lassen, wenn auf dem Client nichts gefunden wird. Angenommen, Sie haben diese eckigen Routen

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

Es ist sinnvoll, die URL nur dann zum Client umzuleiten, wenn sie mit "/ New" oder "/ Show /" beginnt.

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();
}

Dies ist nur ein Beispiel für eine verbesserte Logik. Natürlich hat jede Webanwendung unterschiedliche Anforderungen

Naigel
quelle
1

Ich habe versucht, eine einfache Angular 7-Anwendung für eine Azure-Webanwendung bereitzustellen. Alles hat gut funktioniert, bis Sie die Seite aktualisiert haben. Dabei wurde mir ein 500-Fehler-verschobener Inhalt angezeigt. Ich habe sowohl in den Angular-Dokumenten als auch in einigen Foren gelesen, dass ich meiner bereitgestellten Lösung eine web.config-Datei hinzufügen und sicherstellen muss, dass die Umschreiberegel auf die index.html-Datei zurückgreift. Nach stundenlanger Frustration und Test- und Fehlertests habe ich festgestellt, dass der Fehler recht einfach war: Hinzufügen eines Tags um mein Datei-Markup.

Kelson Martins
quelle
1

Ich hatte ein ähnliches Problem mit Angular und IIS, die beim manuellen Aktualisieren einen 404-Statuscode auslösten, und versuchte die am häufigsten gewählte Lösung, aber das funktionierte bei mir nicht. Ich habe auch eine Reihe anderer Lösungen ausprobiert, die sich mit WebDAV und wechselnden Handlern befassen mussten, und keine funktionierte.

Zum Glück habe ich diese Lösung gefunden und sie hat funktioniert (Teile herausgenommen, die ich nicht brauchte). Wenn also keines der oben genannten Verfahren für Sie funktioniert oder bevor Sie es versuchen, versuchen Sie dies und prüfen Sie, ob dies Ihre eckige Bereitstellung in diesem Problem behebt.

Fügen Sie das Snippet zu Ihrer Webkonfiguration im Stammverzeichnis Ihrer Site hinzu. Nach meinem Verständnis wird der 404-Statuscode aus jeder Vererbung entfernt (applicationhost.config, machine.config), dann ein 404-Statuscode auf Site-Ebene erstellt und als benutzerdefinierte 404-Seite zur Startseite zurückgeleitet.

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