Jak skonfigurować usługi IIS do ponownego zapisywania adresu URL aplikacji AngularJS w trybie HTML5?


140

Mam projekt seed AngularJS i dodałem

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

do pliku app.js. Chcę skonfigurować usługi IIS 7, aby kierować wszystkie żądania do

http://localhost/app/index.html

aby to działało dla mnie. Jak mam to zrobic?

Aktualizacja:

Właśnie odkryłem, pobrałem i zainstalowałem moduł ponownego zapisywania adresów URL w usługach IIS , mając nadzieję, że dzięki temu osiągnięcie mojego celu będzie łatwe i oczywiste.

Aktualizacja 2 :

To chyba podsumowuje to, co próbuję osiągnąć (zaczerpnięte z dokumentacji programisty AngularJS ):

Korzystanie z tego trybu wymaga przepisywania adresu URL po stronie serwera, w zasadzie musisz przepisać wszystkie linki do punktu wejścia aplikacji (np. Index.html)

Aktualizacja 3:

Nadal nad tym pracuję i zdaję sobie sprawę, że NIE muszę przekierowywać (mieć reguł, które przepisują) niektórych adresów URL, takich jak

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

więc wszystko, co znajduje się w katalogach css, js, lib lub częściowych, nie jest przekierowywane. Wszystko inne będzie musiało zostać przekierowane do app / index.html

Czy ktoś wie, jak łatwo to osiągnąć bez konieczności dodawania reguły dla każdego pliku?

Aktualizacja 4:

Mam 2 reguły ruchu przychodzącego zdefiniowane w module ponownego zapisywania adresów URL usług IIS. Pierwsza zasada to:

Reguła ponownego zapisywania adresów URL usług IIS 1

Druga zasada to:

Reguła ponownego zapisywania adresów URL usług IIS 2

Teraz, kiedy przechodzę do localhost / app / view1, ładuje stronę, jednak pliki pomocnicze (te w katalogach css, js, lib i częściowe) są również przepisywane na stronę app / index.html - więc wszystko nadchodzi jako strona index.html bez względu na użyty adres URL. Myślę, że oznacza to, że moja pierwsza reguła, która ma zapobiegać przetwarzaniu tych adresów URL przez drugą regułę, nie działa ... jakieś pomysły? ...ktoś? ...Czuję się taki samotny... :-(


Dzięki za to! Bardzo pomocne!
Ash Clarke

druga zasada jest krytyczna: musisz upewnić się, że jest to routing do strony, która obsługuje AngularJS, app/index.htmla nie app/ jawne jej wyzwalanie. Straciłem 2 godziny życia, zanim to rozgryzłem. :-)
Dexter Legaspi

Inny sposób użycia ASP.NET MVC i dodania do RouteConfig.cs: tours.MapRoute (name: "Default", url: "{* cokolwiek}", defaults: new {controller = "Home", action = "Index", }); a indeks HomeController po prostu zwraca plik („~ / index-anyhinghere.html”, „text / html”); Wtedy Twoja aplikacja stanie się niezależna od usług IIS
Toolkit

Musiałem zainstalować „moduł przepisywania adresu URL z 'Web Installer'”. Jeśli nie ma modułu przepisywania adresu URL, to podczas ponownego ładowania nie będzie działać. ZAINSTALUJ moduł przepisywania adresu URL. :)
Bimal Das

Odpowiedzi:


289

Piszę regułę w web.config po $locationProvider.html5Mode(true)ustawieniu app.js.

Hope, pomaga komuś.

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

W moim index.html dodałem to do <head>

<base href="/">

Nie zapomnij zainstalować usługi IIS URL Rewrite na serwerze.

Również jeśli używasz internetowego interfejsu API i IIS, zadziała to, jeśli twój interfejs API jest www.yourdomain.com/apiustawiony z powodu trzeciego wejścia (trzecia linia warunku).


2
To było bardzo przydatne i okazało się, że jest najbardziej kompletne. Dzięki!
Mario,

2
cieszę się, że pomaga @Mario
Yagiz Ozturk

5
IDEALNY! To był dla mnie trudny problem, spędziłem nad tym wiele godzin. Dzięki! PORADY DLA KAŻDEGO INNEGO: dodałem index.html do <action type = "Rewrite" url "/index.html" /> Następnie w moim index.html (plik katalogu głównego dla Angular SPA, <base href = "/ index .html "/> Kiedy kopiowałem powyższy kod, nie pasował on do mojego <base href />, więc nie działał poprawnie. Ogromne rekwizyty dla wzorca" / (api) "również potykałem się o tę część.
Brad Martin

co, jeśli hostuję w witrynach internetowych platformy Azure?
Zestaw narzędzi

7
To żart, że musimy przeskoczyć przez te obręcze, aby uzyskać routing kątowy. To zabija dla mnie routing kątowy. Co za bałagan.
user441521

38

Reguły ruchu przychodzącego usług IIS, jak pokazano w pytaniu, działają. Musiałem wyczyścić pamięć podręczną przeglądarki i dodać następujący wiersz w górnej części mojej <head>sekcji strony index.html:

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

Dzieje się tak, ponieważ mam więcej niż jedną aplikację na hoście lokalnym, więc localhost/app/view1zamiast tego były kierowane żądania do innych częścilocalhost/myApplication/app/view1

Mam nadzieję, że to komuś pomoże!


1
Nie potrzebowałem tego, ale edycje pytań były świetne. Dzięki!
Ash Clarke

2
To też może być przydatne. Pracował dla mnie podczas ponownego ładowania strony. Bez żadnych specjalnych reguł dla każdego pliku: coderwall.com/p/mycbiq
Per G

jak powiedział @ ash-clarke, nie jest to konieczne, ale i tak jest to dobra praktyka, ponieważ pozwala linkom na stronie być niezależnym od tego, do którego „podkatalogu” należy.
Dexter Legaspi

@PerG Natrafiłem na powyższe rozwiązanie działające, ale nie przy ponownym ładowaniu, oto mój kod: stackoverflow.com/questions/25644287/iis-url-rewrite-rules Jakieś pomysły?
amcdnl

Nie wiem lub nie próbowałem odfiltrować niektórych połączeń. Rozwiązaniem byłoby posiadanie API w innej domenie itp. Ale być może nie jest to rozwiązanie dla u. Ale możesz nadal pytać w moim linku powyżej. A może autor może ci odpowiedzieć?
Według G

11

W moim przypadku otrzymywałem 403.14 po skonfigurowaniu prawidłowych reguł przepisywania. Okazuje się, że miałem katalog o tej samej nazwie, co jedna z moich tras URL. Po usunięciu reguły przepisywania IsDirectory moje trasy działały poprawnie. Czy istnieje przypadek, w którym usunięcie negacji katalogu może spowodować problemy? Nie mogę wymyślić żadnego w moim przypadku. Jedyny przypadek, jaki przychodzi mi do głowy, to przeglądanie katalogu za pomocą aplikacji.

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

10

Problem z spełnieniem tylko tych dwóch warunków:

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

jest to, że działają tylko tak długo, jak długo {REQUEST_FILENAME} istnieją fizycznie na dysku . Oznacza to, że mogą istnieć scenariusze, w których żądanie niepoprawnie nazwanego częściowego widoku zwróci stronę główną zamiast 404, co spowodowałoby dwukrotne załadowanie angulara (aw niektórych scenariuszach może spowodować nieprzyjemną nieskończoną pętlę).

Dlatego zaleca się stosowanie pewnych bezpiecznych reguł „awaryjnych”, aby uniknąć tych trudnych do rozwiązania problemów:

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

lub warunek, który pasuje do dowolnego zakończenia pliku :

<conditions>
  <!-- ... -->
  <add input="{REQUEST_FILENAME}" pattern=".*\.[\d\w]+$" negate="true" />
</conditions>

1
Po tym wszystkim moja witryna ładuje się dobrze, ale jeśli jestem na ścieżce wzdłuż trasy, mam problemy. Tak więc, jeśli ścieżka w mojej przeglądarce to: 10.34.34.46/jbvdev/documents/BC498484 Początkowo wygląda to dobrze, ale jeśli kliknę odśwież, wszystko się psuje, ponieważ zaczyna szukać css i js pod adresem 10.34.34.46/jbvdev/documents / css lub 10.34.34.46/jbvdev/documents/js Czy ktoś wie, jak rozwiązać ten problem?
Michael Mahony,

1

Najłatwiejszym sposobem, jaki znalazłem, jest po prostu przekierowanie żądań, które wyzwalają 404, do klienta. Odbywa się to poprzez dodanie hashtagu, nawet jeśli $locationProvider.html5Mode(true)jest ustawiony.

Ta sztuczka działa w środowiskach z większą liczbą aplikacji internetowych w tej samej witrynie sieci Web i wymagających ograniczeń integralności adresu URL (zewnętrzne uwierzytelnianie EG). Oto krok po kroku, jak to zrobić

index.html

Ustaw <base>element prawidłowo

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

web.config

Pierwsze przekierowanie 404 na stronę niestandardową, na przykład „Strona główna / Błąd”

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

Kontroler domowy

Zaimplementuj proste ActionResultdo „przetłumaczenia” dane wejściowe w trasie po stronie klienta.

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

To jest najprostszy sposób.


Jest możliwe (zalecane?) Rozszerzenie funkcji Error o ulepszoną logikę, aby przekierować 404 do klienta tylko wtedy, gdy adres URL jest prawidłowy i pozwolić 404 wyzwalać się normalnie, gdy nic nie zostanie znalezione na kliencie. Powiedzmy, że masz te kątowe trasy

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

Przekierowywanie adresu URL do klienta ma sens tylko wtedy, gdy zaczyna się od „/ New” lub „/ Show /”

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

To tylko przykład ulepszonej logiki, oczywiście każda aplikacja internetowa ma inne potrzeby


1

Próbowałem wdrożyć prostą aplikację Angular 7 w aplikacji internetowej platformy Azure. Wszystko działało dobrze, aż do momentu odświeżenia strony. Robiąc to, pokazywał mi błąd 500 - przeniesiona treść. Przeczytałem zarówno w dokumentacji Angular, jak i na kilku dobrych forach, że muszę dodać plik web.config do mojego wdrożonego rozwiązania i upewnić się, że reguła przepisywania powraca do pliku index.html. Po wielu godzinach frustracji i testów metodą prób i błędów stwierdziłem, że błąd był dość prosty: dodanie tagu wokół mojego znacznika pliku.


1

Miałem podobny problem z Angularem i IIS wyrzucającymi kod stanu 404 podczas ręcznego odświeżania i wypróbowałem rozwiązanie najczęściej wybierane, ale to nie zadziałało. Wypróbowano również kilka innych rozwiązań, które musiały radzić sobie z WebDAV i zmieniającymi się programami obsługi, ale żadne nie działało.

Na szczęście znalazłem to rozwiązanie i zadziałało (wyjąłem części, których nie potrzebowałem). Więc jeśli żadne z powyższych nie działa dla Ciebie lub nawet przed ich wypróbowaniem, spróbuj tego i sprawdź, czy to rozwiązuje problem z wdrożeniem kątowym w przypadku iis.

Dodaj fragment kodu do swojej konfiguracji internetowej w katalogu głównym swojej witryny. Z mojego zrozumienia usuwa kod stanu 404 z dowolnego dziedziczenia (applicationhost.config, machine.config), a następnie tworzy kod stanu 404 na poziomie witryny i przekierowuje z powrotem na stronę główną jako niestandardową stronę 404.

<?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>
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.