使用启用了 Html5 模式的 Angular Ui 路由器时,页面重新加载失败
Page reload fails when using Angular Ui Router with Html5 mode enabled
我在我的 angular 应用程序中使用 Angular UI 路由器,并且我启用了 HTML5 模式以通过使用从 URL 中删除 #配置中的 $locationProvider.
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'
})
});
我还在 index.html 文件中设置了 <base href="/" />
标签。路由工作正常,我可以导航到页面并删除#,但是当我使用浏览器上的重新加载按钮刷新页面时,会出现 404 错误响应。
为什么会发生这种情况,我该如何修复它并启用 HTML5 模式以获得正确的 URLs
您需要在服务器端设置url重写
对于 apache,它将类似于:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.html
在 .htaccess
文件中(确保 mod_rewrite
apache 模块已启用)
并像这样为 nginx 配置:
location / {
....
try_files $uri $uri/ /index.html =404;
}
Kasun,发生这种情况的原因是因为您正试图从您的子路由之一刷新页面(与 ui-router 无关)。
基本上,如果您请求 www.yourdomain.com/
,您可能会将服务器设置为 return index.html
,这会引导您的 angular 应用程序。加载应用程序后,任何进一步的 url 更改都会考虑 html5Mode
并通过 ui-router.
更新您的页面
当您重新加载页面时,angular 应用程序不再有效,因为它尚未加载,因此如果您尝试加载子路由(例如:www.yourdomain.com/someotherpage
),则您的服务器不知道如何处理 /someotherpage
并且可能 returns 404
或其他一些错误。
您需要做的是将您的服务器配置为 return 您的 angular 应用程序 所有 路由。我主要使用 node/express,所以我会这样做:
app.get('*', function(req, res, next) {
// call all routes and return the index.html file here
}
注意:我通常使用这样的东西作为最后的包罗万象,但是我还在它上面包含其他路由,用于请求静态文件、网络爬虫和任何其他需要的特定路由得到处理。
首先制作 .htaccess 文件然后复制粘贴这些代码
<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
无法详细解释为什么会发生这种情况,但我可以向您描述我解决此问题的方法。所以我将 UrlRewriterFilter 用于我的 SpringMvc 后端。 Angular 通用模块配置:
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)
;
});
我的主页,index.html:
<html ng-app="ilonaChatGeneralModule" ng-controller="ilonaChatGeneralCtrl">
<head>
<base href="/">
...
</head>
<body>
<div>
<div ui-view=""></div>
</div>
</body>
</html>
这是前端。对于后端,我使用了 UrlRewriteFilter,你可以通过以下 maven 依赖项获得它:
<dependency>
<groupId>org.tuckey</groupId>
<artifactId>urlrewritefilter</artifactId>
<version>4.0.3</version>
</dependency>
我已经通过以下方式将它添加到我的 SpringMVC WebAppInitializer 中:
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);
}
}
此过滤器需要您的 WEB-INF 目录下的 urlrewrite.xml 文件(似乎在可配置但默认位置 - 此处)。此文件的内容:
<!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>
我没有仔细阅读手册,但我怀疑这个想法是在您使用 http://yourhost:xxxx/privateroom ur app try to find physicaly existing view http://yourhost:xxxx/privateroom 刷新浏览器时产生的。但是它不存在。当您将其重定向到您的基页时,angular 将使用其状态定义将正确的 link 构建到物理文件。我在理论上可能会犯错,但在实践中是可行的
注意到一条询问有关 IIS 的评论 - 尚未在此处看到它 - 但这就是我的工作方式。确保已安装 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>`
如果您无法配置您的服务器,请使用以下内容配置您的 web.xml 以在用户处于 html5 推送路径时处理刷新。
<error-page>
<!-- Mapping a 404 when user refreshes with an html5 push route-->
<error-code>404</error-code>
<location>/index.html</location>
</error-page>
对我来说最简单的方法是:
在index.html
中使用<base href="/admin/"></base>
我正在为我的管理页面做这件事
我在我的 angular 应用程序中使用 Angular UI 路由器,并且我启用了 HTML5 模式以通过使用从 URL 中删除 #配置中的 $locationProvider.
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'
})
});
我还在 index.html 文件中设置了 <base href="/" />
标签。路由工作正常,我可以导航到页面并删除#,但是当我使用浏览器上的重新加载按钮刷新页面时,会出现 404 错误响应。
为什么会发生这种情况,我该如何修复它并启用 HTML5 模式以获得正确的 URLs
您需要在服务器端设置url重写
对于 apache,它将类似于:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.html
在 .htaccess
文件中(确保 mod_rewrite
apache 模块已启用)
并像这样为 nginx 配置:
location / {
....
try_files $uri $uri/ /index.html =404;
}
Kasun,发生这种情况的原因是因为您正试图从您的子路由之一刷新页面(与 ui-router 无关)。
基本上,如果您请求 www.yourdomain.com/
,您可能会将服务器设置为 return index.html
,这会引导您的 angular 应用程序。加载应用程序后,任何进一步的 url 更改都会考虑 html5Mode
并通过 ui-router.
当您重新加载页面时,angular 应用程序不再有效,因为它尚未加载,因此如果您尝试加载子路由(例如:www.yourdomain.com/someotherpage
),则您的服务器不知道如何处理 /someotherpage
并且可能 returns 404
或其他一些错误。
您需要做的是将您的服务器配置为 return 您的 angular 应用程序 所有 路由。我主要使用 node/express,所以我会这样做:
app.get('*', function(req, res, next) {
// call all routes and return the index.html file here
}
注意:我通常使用这样的东西作为最后的包罗万象,但是我还在它上面包含其他路由,用于请求静态文件、网络爬虫和任何其他需要的特定路由得到处理。
首先制作 .htaccess 文件然后复制粘贴这些代码
<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
无法详细解释为什么会发生这种情况,但我可以向您描述我解决此问题的方法。所以我将 UrlRewriterFilter 用于我的 SpringMvc 后端。 Angular 通用模块配置:
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)
;
});
我的主页,index.html:
<html ng-app="ilonaChatGeneralModule" ng-controller="ilonaChatGeneralCtrl">
<head>
<base href="/">
...
</head>
<body>
<div>
<div ui-view=""></div>
</div>
</body>
</html>
这是前端。对于后端,我使用了 UrlRewriteFilter,你可以通过以下 maven 依赖项获得它:
<dependency>
<groupId>org.tuckey</groupId>
<artifactId>urlrewritefilter</artifactId>
<version>4.0.3</version>
</dependency>
我已经通过以下方式将它添加到我的 SpringMVC WebAppInitializer 中:
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);
}
}
此过滤器需要您的 WEB-INF 目录下的 urlrewrite.xml 文件(似乎在可配置但默认位置 - 此处)。此文件的内容:
<!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>
我没有仔细阅读手册,但我怀疑这个想法是在您使用 http://yourhost:xxxx/privateroom ur app try to find physicaly existing view http://yourhost:xxxx/privateroom 刷新浏览器时产生的。但是它不存在。当您将其重定向到您的基页时,angular 将使用其状态定义将正确的 link 构建到物理文件。我在理论上可能会犯错,但在实践中是可行的
注意到一条询问有关 IIS 的评论 - 尚未在此处看到它 - 但这就是我的工作方式。确保已安装 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>`
如果您无法配置您的服务器,请使用以下内容配置您的 web.xml 以在用户处于 html5 推送路径时处理刷新。
<error-page>
<!-- Mapping a 404 when user refreshes with an html5 push route-->
<error-code>404</error-code>
<location>/index.html</location>
</error-page>
对我来说最简单的方法是:
在index.html
中使用<base href="/admin/"></base>
我正在为我的管理页面做这件事