¿Cómo configuro IIS para reescribir URL de una aplicación AngularJS en modo HTML5?


140

Tengo el proyecto semilla AngularJS y he agregado

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

al archivo app.js. Quiero configurar IIS 7 para enrutar todas las solicitudes a

http://localhost/app/index.html

para que esto funcione para mí ¿Cómo hago esto?

Actualizar:

Acabo de descubrir, descargar e instalar el módulo de reescritura de URL de IIS , esperando que esto haga que sea fácil y obvio lograr mi objetivo.

Actualización 2 :

Supongo que esto resume lo que estoy tratando de lograr (tomado de la documentación de AngularJS Developer ):

El uso de este modo requiere la reescritura de URL en el lado del servidor, básicamente debe reescribir todos sus enlaces al punto de entrada de su aplicación (por ejemplo, index.html)

Actualización 3:

Todavía estoy trabajando en esto y me doy cuenta de que NO necesito redirigir (tener reglas que reescriban) ciertas URL como

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

así que todo lo que está en los directorios css, js, lib o parciales no se redirige. Todo lo demás deberá ser redirigido a app / index.html

¿Alguien sabe cómo lograr esto fácilmente sin tener que agregar una regla para cada archivo?

Actualización 4:

Tengo 2 reglas entrantes definidas en el módulo IIS URL Rewrite. La primera regla es:

Regla de entrada de reescritura de URL de IIS 1

La segunda regla es:

Regla de entrada 2 de reescritura de URL de IIS

Ahora, cuando navego a localhost / app / view1, carga la página, sin embargo, los archivos de soporte (los que están en los directorios css, js, lib y partials) también se están reescribiendo en la página app / index.html, por lo que todo está llegando volver a la página index.html sin importar qué URL se utiliza. Supongo que esto significa que mi primera regla, que se supone que evita que estas URL sean procesadas por la segunda regla, no está funcionando ... ¿alguna idea? ...¿nadie? ...Me siento tan sola... :-(


¡Gracias por esto! ¡Muy útil!
Ash Clarke

la segunda regla es crítica: debe asegurarse de que esté enrutando app/index.htmly no app/ activar explícitamente la página que sirve AngularJS. Perdí 2 horas de mi vida antes de resolverlo. :-)
Dexter Legaspi

Otra forma de usar ASP.NET MVC y agregar a RouteConfig.cs: routes.MapRoute (nombre: "Predeterminado", url: "{* cualquier cosa}", valores predeterminados: nuevo {controlador = "Inicio", acción = "Índice", }); y su índice HomeController solo devuelve Archivo ("~ / index-anyhinghere.html", "text / html"); Entonces su aplicación se vuelve independiente de IIS
Toolkit

Tuve que instalar el "módulo de reescritura de URL del 'Instalador web'". Si el módulo de reescritura de url no está allí, durante la recarga, la reescritura no funcionará. INSTALE el módulo de reescritura de URL. :)
Bimal Das

Respuestas:


289

Escribo una regla en web.config después de que $locationProvider.html5Mode(true)se establece app.js.

Esperanza, ayuda a alguien.

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

En mi index.html agregué esto a <head>

<base href="/">

No olvide instalar IIS URL Rewrite en el servidor.

Además, si usa API web e IIS, esto funcionará si su API se encuentra en www.yourdomain.com/apila tercera entrada (tercera línea de condición).


2
Esto fue muy útil y me pareció que era el más completo. ¡Gracias!
Mario

2
Me alegro de que ayude @ Mario
Yagiz Ozturk

55
¡PERFECTO! Este fue un tema difícil para mí, pasé horas trabajando en esto. ¡Gracias! ASESORAMIENTO A CUALQUIER OTRO: Agregué index.html a <action type = "Rewrite" url "/index.html" /> Luego en mi index.html (archivo de directorio raíz para Angular SPA, el <base href = "/ index .html "/> Cuando hice frente al código anterior, no coincidía con mi <base href /> por lo que no funcionó correctamente. Enormes accesorios para el patrón" / (api) "también, seguí tropezando en esa parte.
Brad Martin

¿Qué sucede si alojo en sitios web de Azure?
Kit de herramientas del

77
Es una broma que tenemos que saltar a través de estos aros para el enrutamiento angular. Esto mata el enrutamiento angular para mí. Que desastre.
user441521

38

Las reglas de entrada de IIS como se muestra en la pregunta SÍ funcionan. Tuve que borrar el caché del navegador y agregar la siguiente línea en la parte superior de mi <head>sección de la página index.html:

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

Esto se debe a que tengo más de una aplicación en localhost y, por lo tanto, se enviaron solicitudes a otros parciales en localhost/app/view1lugar delocalhost/myApplication/app/view1

¡Ojalá esto ayude a alguien!


1
No necesitaba esto, pero las ediciones de preguntas fueron geniales. ¡Gracias!
Ash Clarke

2
También esto puede ser útil. Me funcionó al volver a cargar la página. Sin reglas especiales para cada archivo: coderwall.com/p/mycbiq
Por G

como dijo @ ash-clarke, no es necesario, pero de todos modos es una buena práctica, ya que permite que los enlaces de la página sean independientes de a qué "subdirectorio" pertenece.
Dexter Legaspi

@PerG Me encontré con la solución anterior trabajando pero no en la recarga, aquí está mi código: stackoverflow.com/questions/25644287/iis-url-rewrite-rules ¿ Alguna idea?
amcdnl

No sé o he intentado filtrar ciertas llamadas. Una forma de evitarlo sería tener API en otro dominio, etc. Pero quizás esta no sea una solución para usted. Pero puedes seguir preguntando en mi enlace de arriba. ¿Y quizás el autor pueda responderte?
Por G

11

En mi caso, seguí obteniendo un 403.14 después de haber configurado las reglas correctas de reescritura. Resulta que tenía un directorio que tenía el mismo nombre que una de mis rutas URL. Una vez que eliminé la regla de reescritura de IsDirectory, mis rutas funcionaron correctamente. ¿Hay algún caso en el que eliminar la negación del directorio pueda causar problemas? No puedo pensar en ninguno en mi caso. El único caso que se me ocurre es si puede navegar por un directorio con su aplicación.

<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

El problema con solo tener estas dos condiciones:

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

es que funcionan solo mientras {REQUEST_FILENAME} exista físicamente en el disco . Esto significa que puede haber escenarios en los que una solicitud de una vista parcial con un nombre incorrecto devolvería la página raíz en lugar de un 404, lo que provocaría que angular se cargara dos veces (y en ciertos escenarios puede causar un bucle infinito desagradable).

Por lo tanto, se recomendarían algunas reglas seguras de "respaldo" para evitar estos problemas difíciles de solucionar:

  <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 condición que coincide con cualquier final de archivo :

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

1
Con todo esto en su lugar, mi sitio se carga muy bien, pero si estoy en un camino a lo largo de la ruta tengo problemas. Por lo tanto, si la ruta en mi navegador es: 10.34.34.46/jbvdev/documents/BC498484 Inicialmente aparece bien, pero si presiono actualizar, todo se rompe porque comienza a buscar css y js en 10.34.34.46/jbvdev/documents / css o 10.34.34.46/jbvdev/documents/js ¿Alguien sabe cómo resolver esto?
Michael Mahony el

1

La forma más fácil que encontré es simplemente redirigir las solicitudes que activan 404 al cliente. Esto se hace agregando un hashtag incluso cuando $locationProvider.html5Mode(true)está configurado.

Este truco funciona para entornos con más aplicaciones web en el mismo sitio web y que requieren restricciones de integridad de URL (por ejemplo, autenticación externa). Aquí está paso a paso cómo hacerlo

index.html

Establecer el <base>elemento correctamente

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

web.config

Primero redirija 404 a una página personalizada, por ejemplo "Inicio / Error"

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

Controlador de inicio

Implemente una entrada simple ActionResultpara "traducir" en una ruta del lado del cliente.

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

Esta es la forma más simple.


Es posible (¿aconsejable?) Mejorar la función Error con alguna lógica mejorada para redirigir 404 al cliente solo cuando la url es válida y dejar que el 404 se active normalmente cuando no se encuentre nada en el cliente. Digamos que tienes estas rutas angulares

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

Tiene sentido redirigir la URL al cliente solo cuando comienza con "/ New" o "/ 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();
}

Esto es solo un ejemplo de lógica mejorada, por supuesto, cada aplicación web tiene diferentes necesidades


1

He estado tratando de implementar una aplicación simple de Angular 7 en una aplicación web de Azure. Todo funcionó bien, hasta el punto en que actualizaste la página. Al hacerlo, me estaba presentando un error 500: contenido movido. He leído tanto en los documentos de Angular como en algunos buenos foros, que necesito agregar un archivo web.config a mi solución implementada y asegurarme de que la regla de reescritura recurra al archivo index.html. Después de horas de frustración y pruebas de prueba y error, descubrí que el error era bastante simple: agregar una etiqueta alrededor del marcado de mi archivo.


1

Tuve un problema similar con Angular e IIS lanzando un código de estado 404 en la actualización manual y probé la solución más votada, pero eso no funcionó para mí. También probé un montón de otras soluciones que tenían que lidiar con WebDAV y cambiar los controladores y ninguna funcionó.

Afortunadamente encontré esta solución y funcionó (saqué partes que no necesitaba). Entonces, si ninguno de los anteriores funciona para usted o incluso antes de probarlos, intente esto y vea si eso soluciona su implementación angular en este problema.

Agregue el fragmento a su configuración web en el directorio raíz de su sitio. Según tengo entendido, elimina el código de estado 404 de cualquier herencia (applicationhost.config, machine.config), luego crea un código de estado 404 a nivel del sitio y lo redirige a la página de inicio como una página 404 personalizada.

<?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>
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.