javascript 在启用 Html5 模式的情况下使用 Angular Ui 路由器时页面重新加载失败

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29936224/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 11:21:15  来源:igfitidea点击:

Page reload fails when using Angular Ui Router with Html5 mode enabled

javascriptangularjshtmlangular-ui-router

提问by Kasun Kodagoda

I am using Angular UI Router in my angular app and i have enabled HTML5 mode to remove the # form the URL by using $locationProvider in the config.

我在我的 angular 应用程序中使用了 Angular UI 路由器,并且我已启用 HTML5 模式以通过在配置中使用 $locationProvider 来删除 URL 中的 #。

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

I have also set the <base href="/" />tag in the index.html file as well. The routing works fine and i can navigate to pages and the # is removed but when i refresh the page using the reload button on the browser there is a 404 error response.

我也在<base href="/" />index.html 文件中设置了标签。路由工作正常,我可以导航到页面并删除#,但是当我使用浏览器上的重新加载按钮刷新页面时,会出现 404 错误响应。

enter image description here

在此处输入图片说明

Why is this happening and how can i fix it and have HTML5 mode enabled to have proper URLs

为什么会发生这种情况,我该如何修复它并启用 HTML5 模式以获得正确的 URL

采纳答案by Matt Way

Kasun, the reason that this is occurring is because you are trying to refresh the page from one of your sub routes (has nothing to do with ui-router).

Kasun,发生这种情况的原因是因为您试图从您的子路由之一刷新页面(与 ui-router 无关)。

Basically if you request www.yourdomain.com/you likely have your server setup to return index.htmlwhich bootstraps your angular app. Once the app has loaded, any further url changes take html5Modeinto consideration and update your page via ui-router.

基本上,如果您请求,www.yourdomain.com/您可能会设置服务器以返回index.html引导您的 angular 应用程序的程序。应用程序加载后,任何进一步的 url 更改都会html5Mode考虑并通过 ui-router 更新您的页面。

When you reload your page the angular app is no longer valid as it has not loaded yet, so if you are trying to load a sub route (for example: www.yourdomain.com/someotherpage), then your server does not know how to deal with /someotherpageand likely returns 404or some other error.

当您重新加载页面时,angular 应用程序不再有效,因为它尚未加载,因此如果您尝试加载子路由(例如:)www.yourdomain.com/someotherpage,那么您的服务器不知道如何处理/someotherpage并且可能返回404或某些其他错误。

What you need to do is configure your server to return your angular app for allroutes. I primarily use node/express, so I do something like:

您需要做的是配置您的服务器以返回所有路由的角度应用程序。我主要使用 node/express,所以我做了一些类似的事情:

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

Note: I usually use something like this as a final catch all, however I also include other routes above it for things like requesting static files, web crawlers, and any other specific routes that need to be handled.

注意:我通常使用这样的东西作为最后的全部,但是我也在它上面包含其他路由,例如请求静态文件、网络爬虫和任何其他需要处理的特定路由。

回答by Bogdan Savluk

You need to to setup url rewrite on server side

您需要在服务器端设置 url 重写

for apache it would be something like:

对于 apache,它将类似于:

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

in .htaccessfile(be sure that mod_rewriteapache module is enabled)

.htaccess文件中(确保mod_rewrite启用了apache 模块)

and config like this for nginx:

并为 nginx 配置如下:

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

回答by Mike Jouwstra

Noticed a comment asking about IIS - didn't see it in here yet - but this is how I have mine working. Make sure to have URL Rewrite 2.0 installed.

注意到一条关于 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>`

回答by bramhadev mishra

first make .htaccess file then copy past these code

首先制作 .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

回答by Sobik

Cant explain in details why this happening but I can describe you a way i solved out this problem. So i used UrlRewriterFilter for my SpringMvc backend. Angular general module config :

无法详细解释为什么会发生这种情况,但我可以向您描述我解决此问题的方法。所以我将 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)
        ;
});

My home page, index.html:

我的主页,index.html:

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

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

This is frontend. For backend I used UrlRewriteFilter, you can get it with following maven dependency:

这是前端。对于后端,我使用了 UrlRewriteFilter,您可以使用以下 maven 依赖项获取它:

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

I've added it to my SpringMVC WebAppInitializer in next way:

我已经通过下一种方式将它添加到我的 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);
        }
    }

This filter requires urlrewrite.xml file under ur WEB-INF directory(seems like in configurable but default place - here). Content of this file:

这个过滤器需要你的 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>

I didn't read manuals carefully but i suspect that idea is when you refresh ur browser with http://yourhost:xxxx/privateroomur app try to find physicaly existing view http://yourhost:xxxx/privateroom. But its absent. And when you redirect it to ur base page angular would built correct link to physical file using its states definition. I can mistake in theory but it works in practice

我没有仔细阅读手册,但我怀疑这个想法是当您使用http://yourhost:xxxx/privateroom刷新您的浏览器时,您的应用程序尝试查找物理现有视图http://yourhost:xxxx/privateroom。但它的缺席。当您将其重定向到您的基本页面时,angular 将使用其状态定义构建到物理文件的正确链接。我可以在理论上出错,但它在实践中有效

回答by santon

If you cannot configure your server, configure your web.xml with the following to handle refresh while the user is on an html5 push path.

如果您无法配置您的服务器,请使用以下内容配置您的 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>

回答by AbdulRehman

the easiest way worked for me is:

对我来说最简单的方法是:

use <base href="/admin/"></base>in index.html

<base href="/admin/"></base>在 index.html 中使用

I'm doing it for my admin page

我正在为我的管理页面做这件事