2015-04-29 7 views
13

Używam routera Angular UI w mojej aplikacji kątowej i włączam tryb HTML5, aby usunąć # z adresu URL za pomocą $ locationProvider w konfiguracji.Przeładowanie strony kończy się niepowodzeniem, gdy używany jest Angular Ui Router z włączonym trybem Html5.

var app = angular.module('openIDC', ['ui.router']); 
app.config(function($urlRouterProvider, $stateProvider, $locationProvider) { 

    $locationProvider.html5Mode(true); 

    $urlRouterProvider.otherwise('/'); 

    $stateProvider 
    .state('home', { 
     url: '/', 
     templateUrl: 'views/home.html', 
     controller: 'HomeController' 
    }) 
    .state('login', { 
     url: '/login', 
     templateUrl: 'views/login.html', 
     controller: 'LoginController' 
    }) 
}); 

Mam również ustawić znacznik w pliku index.html <base href="/" /> również. Trasowanie działa dobrze i mogę nawigować do stron, a # jest usuwany, ale kiedy odświeżam stronę za pomocą przycisku ponownego ładowania przeglądarki, pojawia się błąd 404.

enter image description here

Dlaczego tak się dzieje i jak można to naprawić i mieć tryb HTML5 mieć odpowiednie adresy

Odpowiedz

12

Kasun, dlatego, że to dzieje się tak dlatego staramy się odświeżyć stronę z jednej z dróg podrzędnych (nie ma nic wspólnego z UI -Router).

Zasadniczo, jeśli poprosisz o numer www.yourdomain.com/, prawdopodobnie skonfigurujesz serwer, aby zwrócił index.html, który ładuje Twoją aplikację kątową. Po załadowaniu aplikacji wszelkie dalsze zmiany adresu URL biorą pod uwagę adres html5Mode i aktualizują stronę za pośrednictwem interfejsu użytkownika.

Po ponownym załadowaniu strony aplikacja kątowa nie jest już ważna, ponieważ nie została jeszcze załadowana, więc jeśli próbujesz załadować trasę podrzędną (na przykład: www.yourdomain.com/someotherpage), twój serwer nie wie, jak sobie z tym poradzić /someotherpage i prawdopodobnie zwraca 404 lub inny błąd.

Co należy zrobić, to skonfigurować serwer, aby zwrócił aplikację kątową dla wszystkich tras wszystkich. I przede wszystkim używać węzeł/Express, więc robię coś takiego:

app.get('*', function(req, res, next) { 
    // call all routes and return the index.html file here 
} 

Uwaga: Zwykle używam czegoś takiego jak końcowej połowu wszystkich, jednak ja także inne drogi nad nim takie rzeczy jak zainteresowanie plików statycznych, roboty sieciowe i inne specyficzne trasy, którymi należy się posługiwać.

+0

To w zasadzie rozwiązanie. Jedna rzecz, którą chciałbym dodać: jeśli serwer zaplecza obsługuje także dane dynamiczne, np. API, chcesz wyizolować interfejs API z tego przekierowania, więc musisz dodać tę regułę tylko wtedy, gdy plik pasujący do żądania nie istnieje i nie jest dopasowywana żadna inna trasa API. –

+0

Dobra uwaga. Zaktualizowałem moją odpowiedź. Jeśli chodzi o interfejsy API, wolę je uruchamiać z oddzielnego adresu URL/domeny. –

+0

Istnieje dobry przykład NodeJS obsługujących SPA tutaj: http://stackoverflow.com/questions/20396900/angularjs-routing-in-expressjs – mbokil

8

aby prawidłowo ustawień url przepisać po stronie serwera

dla apache, że będzie być coś takiego:

RewriteEngine On 
RewriteBase/
RewriteCond %{REQUEST_FILENAME} !-f 
RewriteCond %{REQUEST_FILENAME} !-d 
RewriteRule . index.html 

w .htaccess plik (pamiętaj, że mod_rewrite moduł Apache włączona)

i config tak dla nginx:

location/{ 
    .... 
    try_files $uri $uri/ /index.html =404; 
} 
+0

Jak zrobić to samo w IIS? –

+1

Nie jestem pewien, nigdy nie robiłem tego w IIS. Ale ta odpowiedź wygląda dobrze: http://stackoverflow.com/questions/12614072/how-do-i-configure-iis-for-url-rewriting-an-angularjs-application-in-html5-mode#26152011 –

3

pierwszy make plik .htaccess skopiuj przeszłość tych kodem

<ifModule mod_rewrite.c> 
    RewriteEngine on 

    # Don't rewrite files or directories 
    RewriteCond %{REQUEST_FILENAME} -f [OR] 
    RewriteCond %{REQUEST_FILENAME} -d 
    RewriteRule^- [L] 


    RewriteRule^your root folder/index.html [L] 
     </ifModule> 


<base url="/"></base> in index.html file 
2

Cant szczegółowo wyjaśnić, dlaczego tak się dzieje, ale mogę opisać wam drogę I rozwiązać ten problem. Więc użyłem UrlRewriterFilter dla mojego zaplecza SpringMvc. Konfiguracja ogólnego modułu kątowego:

var app = angular.module('ilonaChatGeneralModule', 
    [ 
     'ui.router' 
    ]); 

app.config(function($locationProvider){ 
    $locationProvider.html5Mode(true); 
}); 

app.config(function($stateProvider, $urlRouterProvider) { 

    $urlRouterProvider.otherwise('/'); 

    var home = ['/', { 
     url: '/', 
     templateUrl: 'views/userlist.html' 
    }]; 

    var login = ['login', { 
     url: '/login', 
     templateUrl: 'views/login.html' 
    }]; 

    var privateRoom = ['privateroom', { 
     url: '/privateroom', 
     templateUrl: 'views/privateroom.html' 
    }]; 

    $stateProvider 
     .state(home) 
     .state(login) 
     .state(privateRoom) 
     ; 
}); 

Moja strona główna, indeks.html:

<html ng-app="ilonaChatGeneralModule" ng-controller="ilonaChatGeneralCtrl"> 
<head> 
    <base href="/"> 
    ... 

</head> 
<body> 
<div> 
    <div ui-view=""></div> 
</div> 
</body> 
</html> 

To jest frontend. Dla backend użyłem UrlRewriteFilter, można go pobrać z następującej zależności maven:

<dependency> 
     <groupId>org.tuckey</groupId> 
     <artifactId>urlrewritefilter</artifactId> 
     <version>4.0.3</version> 
    </dependency> 

Dodałem go do mojego SpringMVC WebAppInitializer w następny sposób:

package com.sbk.config; 

    import org.springframework.context.ApplicationContext; 
    import org.springframework.web.context.ContextLoaderListener; 
    import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; 
    import org.springframework.web.filter.CharacterEncodingFilter; 
    import org.springframework.web.servlet.DispatcherServlet; 
    import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; 
    import org.tuckey.web.filters.urlrewrite.UrlRewriteFilter; 

    import javax.servlet.*; 
    import java.nio.charset.StandardCharsets; 
    import java.util.EnumSet; 

    public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { 
     private static final String URL_REWRITE_FILTER_NAME = "urlRewrite"; 
     private static final String URL_REWRITE_FILTER_MAPPING = "/*"; 

... 
     @Override 
     public void onStartup(ServletContext servletContext) throws ServletException { 
      super.onStartup(servletContext); 

      FilterRegistration.Dynamic urlReWrite = servletContext.addFilter(URL_REWRITE_FILTER_NAME, new UrlRewriteFilter()); 
      EnumSet<DispatcherType> urlReWriteDispatcherTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD); 
      urlReWrite.addMappingForUrlPatterns(urlReWriteDispatcherTypes, true, URL_REWRITE_FILTER_MAPPING); 
     } 
    } 

Ten filtr wymaga urlrewrite.xml plik w ur Katalog WEB-INF (wygląda jak w konfigurowalnym, ale domyślnym miejscu - tutaj). Zawartość tego pliku:

<!DOCTYPE urlrewrite 
     PUBLIC "-//tuckey.org//DTD UrlRewrite 2.6//EN" 
     "http://www.tuckey.org/res/dtds/urlrewrite2.6.dtd"> 

<urlrewrite> 

    <rule> 
     <from>/login$</from> 
     <to>index.html</to> 
    </rule> 

    <rule> 
     <from>/privateroom$</from> 
     <to>index.html</to> 
    </rule> 

</urlrewrite> 

nie uważnie przeczytać instrukcje, ale podejrzewam, że pomysł jest po odświeżeniu ur przeglądarka z http://yourhost:xxxx/privateroom ur aplikacja spróbować znaleźć physicaly istniejącego widoku http://yourhost:xxxx/privateroom. Ale jest nieobecny. A kiedy przekierujesz go do strony głównej, narożnik zbudowałby poprawne łącze do pliku fizycznego, używając definicji stanów. Mogę się pomylić w teorii, ale działa w praktyce.

3

Zauważyłem komentarz pytający o IIS - jeszcze go tu nie widziałem - ale tak właśnie pracuję. Upewnij się, że zainstalowany jest URL Rewrite 2.0.

<?xml version="1.0" encoding="UTF-8"?> 
<configuration> 
<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> 
</configuration>` 
+0

Pracowałem świetnie, dzięki! – RandomUs1r

2

Jeśli nie można skonfigurować serwer, skonfigurować web.xml z następujących czynności, aby obsłużyć odświeżanie, gdy użytkownik znajduje się na ścieżce html5 Push.

<error-page> 
    <!-- Mapping a 404 when user refreshes with an html5 push route--> 
    <error-code>404</error-code> 
    <location>/index.html</location> 
</error-page>