Come configuro IIS per la riscrittura URL di un'applicazione AngularJS in modalità HTML5?


140

Ho il progetto seed AngularJS e l'ho aggiunto

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

nel file app.js. Voglio configurare IIS 7 per indirizzare tutte le richieste a

http://localhost/app/index.html

in modo che questo funzioni per me. Come faccio a fare questo?

Aggiornare:

Ho appena scoperto, scaricato e installato il modulo di riscrittura URL IIS , sperando che ciò renda facile ed ovvio il raggiungimento del mio obiettivo.

Aggiornamento 2 :

Immagino che questo riassuma ciò che sto cercando di ottenere (tratto dalla documentazione per gli sviluppatori di AngularJS ):

L'uso di questa modalità richiede la riscrittura degli URL sul lato server, in pratica devi riscrivere tutti i tuoi collegamenti al punto di ingresso della tua applicazione (es. Index.html)

Aggiornamento 3:

Ci sto ancora lavorando e mi rendo conto che NON devo reindirizzare (avere regole che riscrivono) determinati URL come

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

quindi tutto ciò che è nelle directory css, js, lib o parziali non viene reindirizzato. Tutto il resto dovrà essere reindirizzato su app / index.html

Qualcuno sa come raggiungerlo facilmente senza dover aggiungere una regola per ogni singolo file?

Aggiornamento 4:

Ho 2 regole in entrata definite nel modulo IIS URL Rewrite. La prima regola è:

Regola 1 in entrata riscrittura URL IIS

La seconda regola è:

Regola di riscrittura in entrata URL IIS 2

Ora quando passo a localhost / app / view1 carica la pagina, tuttavia i file di supporto (quelli nelle directory css, js, lib e parziali) vengono anche riscritti nella pagina app / index.html - quindi tutto sta arrivando torna alla pagina index.html, indipendentemente dall'URL utilizzato. Immagino che questo significhi che la mia prima regola, che dovrebbe impedire a questi URL di essere elaborati dalla seconda regola, non funziona ... qualche idea? ... qualcuno? ...Mi sento così solo... :-(


Grazie per questo! Molto utile!
Ash Clarke,

la seconda regola è fondamentale: devi assicurarti che instradi app/index.htmle non app/ attivare esplicitamente la pagina che serve AngularJS. ho perso 2 ore della mia vita prima di capirlo. :-)
Dexter Legaspi,

Un altro modo per utilizzare ASP.NET MVC e aggiungere a RouteConfig.cs: route.MapRoute (nome: "Predefinito", url: "{* anything}", impostazioni predefinite: nuovo {controller = "Home", action = "Index", }); e il tuo indice HomeController restituisce semplicemente File ("~ / index-anyhinghere.html", "text / html"); Quindi l'app diventa IIS indipendente
Toolkit

Ho dovuto installare "Modulo di riscrittura URL da 'Web Installer'". Se il modulo di riscrittura dell'URL non è presente, durante la ricarica, la riscrittura non funzionerà. INSTALLARE il modulo di riscrittura degli URL. :)
Bimal Das,

Risposte:


289

Scrivo una regola in web.config dopo che $locationProvider.html5Mode(true)è stato impostato app.js.

Spero, aiuti qualcuno.

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

Nel mio index.html l'ho aggiunto a <head>

<base href="/">

Non dimenticare di installare IIS URL Rewrite sul server.

Inoltre, se usi l'API Web e IIS, funzionerà se l'API è attiva a www.yourdomain.com/apicausa del terzo input (terza riga della condizione).


2
Questo è stato molto utile e l'ho trovato il più completo. Grazie!
Mario,

2
felice che aiuti @ Mario
Yagiz Ozturk il

5
PERFETTO! Questo è stato un problema difficile per me, ho passato ore a lavorare su questo. Grazie! CONSIGLI A QUALUNQUE ALTRO: Ho aggiunto index.html a <action type = "Riscrivi" url "/index.html" /> Quindi sul mio index.html (file di directory principale per SPA angolare, <base href = "/ index .html "/> Quando ho copiato il codice sopra, non corrispondeva al mio <base href /> quindi non ha funzionato correttamente. Anche per i motivi" / (api) "enormi, ho continuato a inciampare su quella parte.
Brad Martin,

cosa succede se ospito su siti Web di Azure?
Toolkit,

7
È uno scherzo che dobbiamo saltare attraverso questi cerchi per il routing angolare. Questo uccide il routing angolare per me. Che casino.
user441521

38

Le regole di ingresso IIS, come mostrato nella domanda DO, funzionano. Ho dovuto svuotare la cache del browser e aggiungere la seguente riga nella parte superiore della mia <head>sezione della pagina index.html:

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

Questo perché ho più di un'applicazione in localhost e quindi sono state prese richieste ad altri parziali localhost/app/view1invece dilocalhost/myApplication/app/view1

Spero che questo aiuti qualcuno!


1
Non ne avevo bisogno, ma le modifiche alla domanda erano fantastiche. Grazie!
Ash Clarke,

2
Anche questo può essere utile. Ha funzionato per me quando ho ricaricato la pagina. Senza regole speciali per ogni file: coderwall.com/p/mycbiq
Per G

come ha detto @ ash-clarke, non è necessario ma è comunque una buona pratica in quanto consente ai collegamenti sulla pagina di essere agnostici rispetto alla "sottodirectory" a cui appartiene.
Dexter Legaspi,

@PerG Mi sono imbattuto nella soluzione di cui sopra funzionando ma non alla ricarica, ecco il mio codice: stackoverflow.com/questions/25644287/iis-url-rewrite-rules Qualche idea?
amcdnl,

Non so o ho provato a filtrare determinate chiamate. Un modo per aggirare sarebbe avere API su altri domini ecc. Ma forse questa non è una soluzione per te. Ma puoi continuare a chiedere nel mio link qui sopra. E forse l'autore può risponderti?
Per

11

Nel mio caso ho continuato a ricevere un 403.14 dopo aver impostato le regole di riscrittura corrette. Si scopre che avevo una directory con lo stesso nome di uno dei miei percorsi URL. Una volta rimossa la regola di riscrittura di IsDirectory, i miei percorsi hanno funzionato correttamente. Esiste un caso in cui la rimozione della negazione della directory può causare problemi? Non riesco a pensare a nessuno nel mio caso. L'unico caso che mi viene in mente è se puoi sfogliare una directory con la tua app.

<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

Il problema di avere solo queste due condizioni:

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

è che funzionano solo finché {REQUEST_FILENAME} esiste fisicamente sul disco . Ciò significa che possono esserci scenari in cui una richiesta per una vista parziale con nome errato restituirebbe la pagina principale invece di un 404 che causerebbe il caricamento angolare di due volte (e in alcuni scenari può causare un brutto ciclo infinito).

Pertanto, si consigliano alcune regole di "fallback" sicure per evitare questi problemi difficili da risolvere:

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

o una condizione che corrisponde a qualsiasi fine del file :

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

1
Con tutto questo sul posto il mio sito si carica bene, ma se sono su un percorso lungo il percorso ho problemi. Quindi, se il percorso nel mio browser è: 10.34.34.46/jbvdev/documents/BC498484 Inizialmente si presenta bene, ma se premo aggiorna, tutto si rompe perché inizia a cercare i CSS e JS al 10.34.34.46/jbvdev/documents / css o 10.34.34.46/jbvdev/documents/js Qualcuno sa come risolvere questo?
Michael Mahony,

1

Il modo più semplice che ho trovato è solo di reindirizzare le richieste che attivano 404 sul client. Questo viene fatto aggiungendo un hashtag anche quando $locationProvider.html5Mode(true)è impostato.

Questo trucco funziona per ambienti con più applicazioni Web sullo stesso sito Web e richiede vincoli di integrità dell'URL (ad esempio autenticazione esterna). Ecco come fare passo dopo passo

index.html

Imposta <base>correttamente l' elemento

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

web.config

Innanzitutto reindirizzare 404 a una pagina personalizzata, ad esempio "Home / Errore"

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

Controller domestico

Implementa un ActionResultinput semplice da "tradurre" in una route sul lato client.

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

Questo è il modo più semplice.


È possibile (consigliabile?) Migliorare la funzione Errore con una logica migliorata per reindirizzare 404 al client solo quando url è valido e lasciare che il 404 si attivi normalmente quando non verrà trovato nulla sul client. Supponiamo che tu abbia questi percorsi angolari

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

Ha senso reindirizzare l'URL al client solo quando inizia con "/ Nuovo" o "/ Mostra /"

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

Questo è solo un esempio di logica migliorata, ovviamente ogni applicazione web ha esigenze diverse


1

Ho provato a distribuire una semplice applicazione Angular 7 in un'app Web di Azure. Tutto ha funzionato bene, fino al punto in cui hai aggiornato la pagina. In questo modo, mi è stato presentato un errore di 500: contenuto spostato. Ho letto sia sui documenti angolari sia in alcuni buoni forum, che ho bisogno di aggiungere un file web.config alla mia soluzione distribuita e assicurarmi che la riscrittura della regola fallback nel file index.html. Dopo ore di frustrazione e prove di prova ed errori, ho scoperto che l'errore era piuttosto semplice: l'aggiunta di un tag attorno al markup del mio file.


1

Ho avuto un problema simile con Angular e IIS che lanciavano un codice di stato 404 sull'aggiornamento manuale e ho provato la soluzione più votata ma non ha funzionato per me. Ho anche provato un sacco di altre soluzioni che hanno a che fare con WebDAV e cambiando gestori e nessuno ha funzionato.

Fortunatamente ho trovato questa soluzione e ha funzionato (ho rimosso parti di cui non avevo bisogno). Quindi, se nessuna delle opzioni precedenti funziona per te o anche prima di provarle, prova questo e vedi se questo risolve la tua distribuzione angolare sul problema di IIS.

Aggiungi lo snippet al tuo webconfig nella directory principale del tuo sito. Dalla mia comprensione, rimuove il codice di stato 404 da qualsiasi eredità (applicationhost.config, machine.config), quindi crea un codice di stato 404 a livello di sito e reindirizza alla home page come una pagina 404 personalizzata.

<?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>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.