【问题标题】:Reloading the page gives wrong GET request with AngularJS HTML5 mode使用 AngularJS HTML5 模式重新加载页面会给出错误的 GET 请求
【发布时间】:2013-05-10 07:23:17
【问题描述】:

我想为我的应用启用 HTML5 模式。我已经放了如下代码进行配置,如图here:

return app.config(['$routeProvider','$locationProvider', function($routeProvider,$locationProvider) {

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

    $routeProvider.when('/', {
        templateUrl: '/views/index.html',
        controller: 'indexCtrl'
    });
    $routeProvider.when('/about',{
        templateUrl: '/views/about.html',
        controller: 'AboutCtrl'
    });

如您所见,我使用了$locationProvider.html5mode,并更改了ng-href 的所有链接以排除/#/

问题

目前,我可以转到localhost:9000/ 并查看索引页面并导航到其他页面,例如localhost:9000/about

但是,当我刷新localhost:9000/about 页面时会出现问题。我得到以下输出:Cannot GET /about

如果我查看网络调用:

Request URL:localhost:9000/about
Request Method:GET

如果我先转到localhost:9000/,然后单击导航到/about 的按钮,我会得到:

Request URL:http://localhost:9000/views/about.html

完美呈现页面。

如何在刷新时启用 Angular 以获取正确的页面?

【问题讨论】:

标签: angularjs html angular-routing


【解决方案1】:

我已通过将以下代码 sn-p 添加到 node.js 文件中解决了该问题。

app.get("/*", function (request, response) {
    console.log('Unknown API called');
    response.redirect('/#' + request.url);
});

注意:当我们刷新页面时,它会寻找 API 而不是 Angular 页面(因为 URL 中没有 # 标签。)。使用上面的代码,我用 #

重定向到 url

【讨论】:

    【解决方案2】:

    我有这个我一直在使用的简单解决方案及其工作原理。

    在 App/Exceptions/Handler.php 中

    在顶部添加:

    use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
    

    然后在render方法里面

    public function render($request, Exception $exception)
    {
        .......
    
           if ($exception instanceof NotFoundHttpException){
    
            $segment = $request->segments();
    
            //eg. http://site.dev/member/profile
            //module => member
            // view => member.index
            //where member.index is the root of your angular app could be anything :)
            if(head($segment) != 'api' && $module = $segment[0]){
                return response(view("$module.index"), 404);
            }
    
            return response()->fail('not_found', $exception->getCode());
    
        }
        .......
    
         return parent::render($request, $exception);
    }
    

    【讨论】:

      【解决方案3】:

      最后我找到了一种通过服务器端解决这个问题的方法,因为它更像是 AngularJs 本身的问题,我使用的是 1.5 Angularjs,并且在重新加载页面时遇到了同样的问题。 但是在我的server.js 文件中添加以下代码后,它可以节省我的时间但这不是一个正确的解决方案或不是一个好方法。

      app.use(function(req, res, next){
        var d = res.status(404);
           if(d){
              res.sendfile('index.html');
           }
      });
      

      【讨论】:

        【解决方案4】:

        您的服务器端代码是 JAVA,然后按照以下步骤操作

        第 1 步:下载 urlrewritefilter JAR Click Here 并保存到构建路径 WEB-INF/lib

        第 2 步:启用 HTML5 模式 $locationProvider.html5Mode(true);

        第 3 步:设置基本 URL <base href="/example.com/"/>

        第 4 步:复制并粘贴到您的 WEB.XML

         <filter>
             <filter-name>UrlRewriteFilter</filter-name>
         <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
        </filter>
        
        <filter-mapping>
            <filter-name>UrlRewriteFilter</filter-name>
            <url-pattern>/*</url-pattern>
            <dispatcher>REQUEST</dispatcher>
            <dispatcher>FORWARD</dispatcher>
        </filter-mapping>
        

        第五步:在 WEN-INF/urlrewrite.xml 中创建文件

         <urlrewrite default-match-type="wildcard">
        
        
            <rule>
                    <from>/</from>
                    <to>/index.html</to>
                </rule>
        
            <!--Write every state dependent on your project url-->
            <rule>
                    <from>/example</from>
                    <to>/index.html</to>
                </rule>
            </urlrewrite>
        

        【讨论】:

        【解决方案5】:

        对于 Grunt 和 Browsersync,使用 connect-modrewrite here

        var modRewrite = require('connect-modrewrite');    
        
        
        browserSync: {
                    dev: {
                        bsFiles: {
        
                            src: [
                                'app/assets/css/*.css',
                                'app/*.js',
                                'app/controllers/*.js',
                                '**/*.php',
                                '*.html',
                                'app/jade/includes/*.jade',
                                'app/views/*.html',
                       ],
                    },
                options: {
                    watchTask: true,
                    debugInfo: true,
                    logConnections: true,
                    server: {
                        baseDir :'./',
                        middleware: [
                               modRewrite(['!\.html|\.js|\.jpg|\.mp4|\.mp3|\.gif|\.svg\|.css|\.png$ /index.html [L]'])
                        ]
                    },
        
                    ghostMode: {
                        scroll: true,
                        links: true,
                        forms: true
                            }
                        }
                    }
                },
        

        【讨论】:

        • 这个答案上面有 15 个是很长的时间。 1.npm install connect-modrewrite --save 2.require in gruntfile 3.复制上面的服务器obj
        • 感谢这在 gulp 4 中使用 browserSync 设置对我有用。
        • 很高兴它帮助了@Abdeali Chandanwala!
        • @Omar 我不同意你的观点,像我这样不太高级的用户会从如何将其添加到 gulpfile 中受益。最好记住人们的知识水平不同,仅仅在 gruntfile 中编写 require 不会有帮助,因为我假设他们了解如何将其添加到 gulp。
        【解决方案6】:

        IIS URL重写规则防止html5模式下页面刷新后出现404错误

        对于 Windows 上 IIS 下的 Angular 运行

        <rewrite>
          <rules>
            <rule name="AngularJS" stopProcessing="true">
              <match url=".*" />
              <conditions logicalGrouping="MatchAll">
                <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
              </conditions>
              <action type="Rewrite" url="/" />
            </rule>
          </rules>
        </rewrite>
        

        NodeJS / ExpressJS 路由以防止在 html5 模式下刷新页面后出现 404 错误

        对于 Node/Express 下的 Angular 运行

        var express = require('express');
        var path = require('path');
        var router = express.Router();
        
        // serve angular front end files from root path
        router.use('/', express.static('app', { redirect: false }));
        
        // rewrite virtual urls to angular app to enable refreshing of internal pages
        router.get('*', function (req, res, next) {
            res.sendFile(path.resolve('app/index.html'));
        });
        
        module.exports = router;
        

        更多信息请访问:AngularJS - Enable HTML5 Mode Page Refresh Without 404 Errors in NodeJS and IIS

        【讨论】:

        • 谢谢,IIS 规则帮助我在 azure 中部署了一个 angular2 应用程序,该应用程序无法定向到子路由。
        • 对于 IIS 的解决方案(VS 2013 中的本地主机),我非常感谢您。沮丧地敲了足够长的头,终于找到了这个答案。像魅力一样工作。
        【解决方案7】:

        如果您在 .NET 堆栈中使用带有 AngularJS 的 MVC,那么您必须这样做才能从 url 中删除“#”:

        1. 在 _Layout 页面中设置基本 href:&lt;head&gt; &lt;base href="/"&gt; &lt;/head&gt;

        2. 然后,在您的 Angular 应用配置中添加以下内容:$locationProvider.html5Mode(true)

        3. 上面将从 url 中删除“#”,但页面刷新将不起作用,例如如果您在“yoursite.com/about”页面刷新会给您一个 404。这是因为 MVC 不知道角度路由,并且通过 MVC 模式,它会查找 MVC 页面中不存在的 MVC 中的“关于”路由路径。解决方法是将所有 MVC 页面请求发送到单个 MVC 视图,您可以通过添加捕获所有 url 的路由来做到这一点


        routes.MapRoute(
                name: "App",
                url: "{*url}",
                defaults: new { controller = "Home", action = "Index" }
            );
        

        【讨论】:

          【解决方案8】:

          来自angular docs

          服务器端
          使用此模式需要在服务器端重写 URL,基本上您必须重写所有指向应用程序入口点的链接(例如 index.html)

          这样做的原因是当您第一次访问页面 (/about) 时,例如刷新后,浏览器无法知道这不是一个真实的 URL,因此它会继续加载它。但是,如果您首先加载了根页面和所有 javascript 代码,那么当您导航到 /about 时,Angular 可以在浏览器尝试访问服务器并相应地处理它之前进入那里

          【讨论】:

          • 当它说“您必须重写所有指向应用程序入口点的链接(例如 index.html)”时,这是什么意思?这是否意味着我必须进入我的$routeProvider 并更改每个templateUrl 的路径,例如从templateUrl : '/views/about.html',templateUrl : 'example.com/views/about.html',?
          • 不,您在 $routeProvider 中的规则应该保持原样。答案是指“服务器端”。它指的是更改提供 Angular html 页面的服务器上的路由。在每个请求到达您的 Angular 应用程序之前,它必须首先通过服务器端路由,该路由应该重写所有请求以指向您的 Angular 应用程序入口点(例如“index.html”或“/”,具体取决于您的 Angular路线工作)。
          • 如果我通过某个 CDN 提供我缩小的 index.html,那么这个路由机制将如何执行??
          • apache的好文章,有一个htaccess的例子:ngmilk.rocks/2015/03/09/…
          【解决方案9】:

          我从更大的问题中回答这个问题:

          当我添加 $locationProvider.html5Mode(true) 时,我的网站将不允许粘贴 url。当 html5Mode 为 true 时,如何配置我的服务器工作?

          启用 html5Mode 后,您的网址中将不再使用 # 字符。 # 符号很有用,因为它不需要服务器端配置。没有#,url 看起来更好,但它也需要服务器端重写。下面是一些例子:

          对于使用 AngularJS 进行快速重写,您可以通过以下更新解决此问题:

          app.get('/*', function(req, res) {
          res.sendFile(path.join(__dirname + '/public/app/views/index.html'));
          });
          

          <!-- FOR ANGULAR ROUTING -->
          <base href="/">
          

          app.use('/',express.static(__dirname + '/public'));
          

          【讨论】:

          • 感谢它的解决方案。对于 Nodejs,将 app.js 添加到 app.use('/*', index);
          【解决方案10】:

          Gulp + browserSync:

          通过 npm 安装 connect-history-api-fallback,稍后配置你的服务 gulp 任务

          var historyApiFallback = require('connect-history-api-fallback');
          
          gulp.task('serve', function() {
            browserSync.init({
              proxy: {
                      target: 'localhost:' + port,
                      middleware: [ historyApiFallback() ]
                  }
            });
          });
          

          【讨论】:

            【解决方案11】:

            java + 使用 JHipster 生成的 Angular 应用程序也遇到了同样的问题。 我用过滤器和属性中所有角度页面的列表解决了这个问题:

            application.yml:

            angular-pages:
              - login
              - settings
            ...
            

            AngularPageReloadFilter.java

            public class AngularPageReloadFilter implements Filter {
                @Override
                public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
                    request.getRequestDispatcher("index.html").forward(request, response);
                }
            }
            

            WebConfigurer.java

            private void initAngularNonRootRedirectFilter(ServletContext servletContext,
                                                          EnumSet<DispatcherType> disps) {
                log.debug("Registering angular page reload Filter");
                FilterRegistration.Dynamic angularRedirectFilter =
                        servletContext.addFilter("angularPageReloadFilter",
                                new AngularPageReloadFilter());
                int index = 0;
                while (env.getProperty("angular-pages[" + index + "]") != null) {
                    angularRedirectFilter.addMappingForUrlPatterns(disps, true, "/" + env.getProperty("angular-pages[" + index + "]"));
                    index++;
                }
                angularRedirectFilter.setAsyncSupported(true);
            }
            

            希望对某人有所帮助。

            【讨论】:

              【解决方案12】:

              BrowserSync 和 Gulp 的解决方案。

              来自https://github.com/BrowserSync/browser-sync/issues/204#issuecomment-102623643

              先安装connect-history-api-fallback

              npm --save-dev install connect-history-api-fallback
              

              然后将其添加到您的 gulpfile.js:

              var historyApiFallback = require('connect-history-api-fallback');
              
              gulp.task('serve', function() {
                browserSync.init({
                  server: {
                    baseDir: "app",
                    middleware: [ historyApiFallback() ]
                  }
                });
              });
              

              【讨论】:

              • 哦,快!终于从 Angular 视图开发中解脱了!作为奖励,标准 URL(没有 hash-bang)路由也是如此!谢谢!
              • 像魅力一样工作......非常感谢!
              • 如果您使用特定端口(即 Ionic 空白模板在端口 8100 上运行),只需在服务器后添加一个附加属性,即 server: { ... }, port: 8100,然后只需将 serve 任务添加到您的默认 gulp 任务(即gulp.task('default', ['sass', 'serve']);),然后您可以在运行gulp 刷新页面时运行应用程序而不会出现Cannot GET ... 浏览器错误。请注意,使用ionic serve 运行服务器仍然会遇到错误。
              • 这在我使用开发浏览器同步时效果很好,在产品中我将应用程序作为快速应用程序运行并将所有路由重定向到角度应用程序作为 app.get('*', function(req, res) { req.session.valid = true; res.redirect('/'); });直接给出路径时页面不加载?
              【解决方案13】:

              我在开发环境中使用 apache (xampp),在生产环境中使用 apache, 添加:

              errorDocument 404 /index.html
              

              到.htaccess 为我解决这个问题。

              【讨论】:

                【解决方案14】:
                I solved same problem using modRewrite.  
                AngularJS is reload page when after # changes.  
                But HTML5 mode remove # and invalid the reload.  
                So we should reload manually.
                # install connect-modrewrite
                    $ sudo npm install connect-modrewrite --save
                
                # gulp/build.js
                    'use strict';
                    var gulp = require('gulp');
                    var paths = gulp.paths;
                    var util = require('util');
                    var browserSync = require('browser-sync');
                    var modRewrite  = require('connect-modrewrite');
                    function browserSyncInit(baseDir, files, browser) {
                        browser = browser === undefined ? 'default' : browser;
                        var routes = null;
                        if(baseDir === paths.src || (util.isArray(baseDir) && baseDir.indexOf(paths.src) !== -1)) {
                            routes = {
                                '/bower_components': 'bower_components'
                            };
                        }
                
                        browserSync.instance = browserSync.init(files, {
                            startPath: '/',
                            server: {
                            baseDir: baseDir,
                            middleware: [
                                modRewrite([
                                    '!\\.\\w+$ /index.html [L]'
                                ])
                            ],
                            routes: routes
                            },
                            browser: browser
                        });
                    }
                

                【讨论】:

                  【解决方案15】:

                  我解决了

                  test: {
                          options: {
                            port: 9000,
                            base: [
                              '.tmp',
                              'test',
                              '<%= yeoman.app %>'
                            ],
                           middleware: function (connect) {
                                    return [
                                        modRewrite(['^[^\\.]*$ /index.html [L]']),
                                        connect.static('.tmp'),
                                        connect().use(
                                            '/bower_components',
                                            connect.static('./bower_components')
                                        ),
                                        connect.static('app')
                                    ];
                                }
                          }
                        },
                  

                  【讨论】:

                    【解决方案16】:

                    需要设置的东西很少,因此您在浏览器中的链接看起来像http://yourdomain.com/path,这些是您的角度配置+服务器端

                    1) AngularJS

                    $routeProvider
                      .when('/path', {
                        templateUrl: 'path.html',
                      });
                    $locationProvider
                      .html5Mode(true);
                    

                    2) 服务器端, 只需将.htaccess 放入您的根文件夹并粘贴此

                    RewriteEngine On 
                    Options FollowSymLinks
                    
                    RewriteBase /
                    
                    RewriteCond %{REQUEST_FILENAME} !-f
                    RewriteCond %{REQUEST_FILENAME} !-d
                    RewriteRule ^(.*)$ /#/$1 [L]
                    

                    更多有趣的东西可以阅读关于 angularjs 中的 html5 模式以及每个不同环境所需的配置https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-configure-your-server-to-work-with-html5mode 这个问题也可以帮助你$location / switching between html5 and hashbang mode / link rewriting

                    【讨论】:

                    • 嗨。我尝试了上述解决方案,在我的配置文件中进行了更改。但它仍然不起作用。刷新 URL 仍然会出现“404 NOT FOUND”错误。
                    • 如何在 Websphere 中部署的应用程序中重定向/重写?
                    • 我不明白为什么不!
                    【解决方案17】:

                    正如其他人所说,您需要在服务器上重写路由并设置&lt;base href="/"/&gt;

                    对于gulp-connect

                    npm install connect-pushstate

                    var gulp = require('gulp'),
                      connect = require('gulp-connect'),
                      pushState = require('connect-pushstate/lib/pushstate').pushState;
                    ...
                    connect.server({
                      ...
                      middleware: function (connect, options) {
                        return [
                          pushState()
                        ];
                      }
                      ...
                    })
                    ....
                    

                    【讨论】:

                      【解决方案18】:

                      您需要配置您的服务器以将所有内容重写为 index.html 以加载应用程序:

                      https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#wiki-how-to-configure-your-server-to-work-with-html5mode

                      【讨论】:

                      • 完美,对我来说问题是使用 Laravel Forge 来配置服务器,该服务器的相关 nginx 行为try_files $uri $uri/ /index.php?...,而不是所需的index.html。感谢您的链接!
                      • 应该是最佳答案,无论您的服务器如何,都能提供每种情况。与 NodeJS 完美配合
                      【解决方案19】:

                      我们在 Express 中有一个服务器重定向:

                      app.get('*', function(req, res){
                          res.render('index');
                      });
                      

                      我们仍然遇到页面刷新问题,即使我们添加了&lt;base href="/" /&gt;

                      解决方案:确保您在页面中使用真实链接进行导航;不要在 URL 中输入路由,否则您将获得页面刷新。 (愚蠢的错误,我知道)

                      :-P

                      【讨论】:

                      • 但是由于这个每个http请求都会有索引文件,例如:/getJsonFromServer - 一个返回数据的http请求,但是由于这个配置它也会返回索引页面
                      【解决方案20】:

                      我发现了更好的 Grunt 插件,如果你的 index.html 和 Gruntfile.js 在同一个目录下,它就可以工作;

                      https://npmjs.org/package/grunt-connect-pushstate
                      

                      之后在你的 Gruntfile 中:

                       var pushState = require('grunt-connect-pushstate/lib/utils').pushState;
                      
                      
                          connect: {
                          server: {
                            options: {
                              port: 1337,
                              base: '',
                              logger: 'dev',
                              hostname: '*',
                              open: true,
                              middleware: function (connect, options) {
                                return [
                                  // Rewrite requests to root so they may be handled by router
                                  pushState(),
                                  // Serve static files
                                  connect.static(options.base)
                                ];
                              }
                            },
                          }
                      },
                      

                      【讨论】:

                      • 不推荐使用 grunt-connect-pushstate 模块
                      【解决方案21】:

                      我遇到了类似的问题,我通过以下方式解决了它:

                      • 在索引页面中使用&lt;base href="/index.html"&gt;

                      • 在我的节点/Express 服务器中使用 catch all route 中间件如下(放在路由器之后):

                      app.use(function(req, res) {
                          res.sendfile(__dirname + '/Public/index.html');
                      });
                      

                      我认为这应该可以让您启动并运行。

                      如果您使用 apache 服务器,您可能需要修改链接。做起来并不难。只需对配置文件进行一些更改。

                      所有这些都假设您在 angularjs 上启用了 html5mode。 现在。请注意,在 Angular 1.2 中,实际上不再建议声明基本 url。

                      【讨论】:

                      • 此解决方案适用于我的设置:&lt;base href="/"&gt; 并添加您建议的 Express 路由。非常感谢。
                      • Tahir Chad,在实现&lt;base href="/index.html"&gt; 之后,您还需要使用服务器端 url-rewrite 吗?
                      • 是的,您可以将 url 重写视为一种设置应用程序/网站的基本 url 的方式(包括域)。 'base url' html 语句只是一种确保所有相关链接都正确地从同一个基础派生的方法。如果您的链接是绝对的,则基本 url 不是绝对必要的。
                      • 当我使用它时,我只是在页面上看到了html代码本身,而不是呈现为实际页面。
                      • 这个答案值得三颗星!感谢您提供如此直截了当的答案。其他人只是重复关于“需要进行服务器重定向”的同一行。
                      【解决方案22】:

                      我编写了一个简单的连接中间件,用于在 grunt 项目上模拟 url 重写。 https://gist.github.com/muratcorlu/5803655

                      你可以这样使用:

                      module.exports = function(grunt) {
                        var urlRewrite = require('grunt-connect-rewrite');
                      
                        // Project configuration.
                        grunt.initConfig({
                          connect: {
                            server: {
                              options: {
                                port: 9001,
                                base: 'build',
                                middleware: function(connect, options) {
                                  // Return array of whatever middlewares you want
                                  return [
                                    // redirect all urls to index.html in build folder
                                    urlRewrite('build', 'index.html'),
                      
                                    // Serve static files.
                                    connect.static(options.base),
                      
                                    // Make empty directories browsable.
                                    connect.directory(options.base)
                                  ];
                                }
                              }
                            }
                          }
                        })
                      };
                      

                      【讨论】:

                      • $routeProvider中是否有手动完成URL重写的方法?
                      • 我在尝试运行它时收到urlRewrite is not defined 警告,我很难找到可以使用的正确连接和重写。
                      • 显示错误“对象构建没有方法 'initConfig' 使用 --force 继续。”
                      【解决方案23】:

                      我相信您的问题与服务器有关。关于 HTML5 模式的角度文档(在您问题中的链接中)指出:

                      服务器端 使用此模式需要在服务器端重写 URL,基本上您必须重写所有指向应用程序入口点的链接(例如 index.html)

                      我相信您需要设置从 /about 到 / 的 url 重写。

                      【讨论】:

                      • 感谢您的回答。因此,当我在 about 页面上刷新时,服务器应该将 url 重写为 / ?问题是我使用的是不同域上的 rails 后端。所有通信都是通过 API 调用进行的。我将如何进行这些 URL 重写?
                      • 问题是您的应用程序在您的服务器路由 / 上可用,因此当您刷新 /about 的 url 时,浏览器将从您的服务器请求 /about 的任何页面(在这种情况下,您有那里没有页面,因此您需要将它们重定向回来)。
                      猜你喜欢
                      • 2016-10-15
                      • 2022-01-25
                      • 2010-11-16
                      • 1970-01-01
                      • 2016-04-20
                      • 2013-07-07
                      • 2015-03-23
                      相关资源
                      最近更新 更多