使用AngularJS HTML5模式重新加载页面会给出错误的GET请求


193

我想为我的应用启用HTML5模式。我已经把下面的代码的配置,如图所示在这里

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以获得正确的页面?



1
我为我解决。看到这里stackoverflow.com/questions/22394014/...
萨沙B.

Answers:


99

角度文档

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

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


21
当它显示“您必须重写到应用程序入口点的所有链接(例如index.html)”时,这是什么意思?这是否意味着我必须进入$routeProvider并更改每个路径(templateUrl例如从templateUrl : '/views/about.html',到)templateUrl : 'example.com/views/about.html',

7
不,您在$ routeProvider中的规则应保持不变。答案是指“服务器端”。它是指在提供您的html页面的服务器上更改路由。在每个请求到达您的角度应用程序之前,它必须首先通过服务器端路由,该路由应重写所有请求以指向您的角度应用程序入口点(例如,“ index.html”或“ /”,具体取决于您的角度)路线工作)。
marni 2014年

如果我通过一些CDN提供缩小的index.html,那么该路由机制将如何执行?
CrazyGeek


5
对于apache的好文章,有一个htaccess 示例
6

63

几乎没有什么需要设置的,因此您在浏览器中的链接看起来像http://yourdomain.com/path,这些是您的Angular配置+服务器端

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 /在html5和hashbang模式之间切换/链接重写


你好 我尝试了上述解决方案,在配置文件中进行了更改。但仍然无法正常工作。刷新URL仍会出现“ 404 NOT FOUND”错误。
kTn

如何在Websphere中部署的应用程序中重定向/重写?
加里

我不明白为什么不!
玩家

36

我有一个类似的问题,我通过以下方法解决了:

  • 使用<base href="https://stackoverflow.com/index.html">在索引页

  • 如下使用我的节点/ Express服务器中的所有路由中间件(将其放在路由器之后):

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

我认为这应该可以使您正常运行。

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

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


1
此解决方案对我有效,它具有以下设置: <base href="https://stackoverflow.com/">并添加了您建议的Express路由。Mucho谢谢。
吉拉德·佩莱格

Tahir Chad,实现了<base href="https://stackoverflow.com/index.html">吗?
科迪2014年

是的,您可以看到url重写是一种以石头(包括域)设置应用程序/网站的基本url的方式。'base url'html语句只是确保所有相对链接均正确地源自同一基础的一种方法。如果您的链接是绝对的,则基本URL不是绝对必要的。
塔伊2014年

1
使用此功能时,我只会在页面上看到html代码本身,而不是呈现为实际页面。
挪亚2015年

2
这个答案值得三星级!感谢您提供如此简单的答案。其他所有人都重复关于“需要进行服务器重定向”的同一行。
艾哈迈德·哈克

27

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视图开发中解脱了!另外,标准网址(没有哈希爆炸)也可以!谢谢!
一点一点的

1
就像魅力一样……非常感谢!
Nishanth Nair

1
如果您使用的是特定端口(例如,Ionic空白模板在端口8100上运行),则只需在服务器ie之后添加一个附加属性server: { ... }, port: 8100,然后将serve任务添加到默认的gulp任务(即gulp.task('default', ['sass', 'serve']);),然后即可运行该应用程序Cannot GET ...通过运行刷新页面时没有浏览器错误gulp。请注意,使用来运行服务器ionic serve仍然会遇到错误。
卢克·斯科恩

当我使用开发浏览器同步时,这很好用,在生产中,我将应用程序作为快速应用程序运行,并将所有路由重定向为app.get('*',function(req,res){req.session.valid = true ; res.redirect('/');}); 直接给路径时页面不加载?
AJ先生

13

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

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


1
完美,对我来说,问题是使用Laravel Forge来配置服务器,该服务器具有相关的nginx行,try_files $uri $uri/ /index.php?...而不是所需的行index.html。感谢您的链接!
CJ汤普森

应该是最佳答案,无论您的服务器如何都应提供。与NodeJS完美协作
Joe Lloyd

10

我编写了一个简单的connect中间件,用于模拟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)
            ];
          }
        }
      }
    }
  })
};

是否有手动方法来完成中的URL重写$routeProvider

1
urlRewrite尝试运行它时,我得到未定义的警告,并且我很难找到可以使用的正确连接方式。

显示一个错误“对象构建没有方法'initConfig'使用--force继续。”
edonbajrami

8

如果您在带有AngularJS的MVC的.NET堆栈中,则必须执行以下操作以从URL中删除“#”:

  1. 在_Layout页面中设置基本href: <head> <base href="https://stackoverflow.com/"> </head>

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

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


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

8

IIS URL重写规则可防止在html5mode中刷新页面后出现404错误

对于Windows上的IIS下的角度运行

<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路由以在html5mode中刷新页面后防止404错误

在Node / Express下进行角度运行

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-在NodeJS和IIS中启用HTML5模式页面刷新而无404错误


谢谢,IIS规则帮助我在Azure中部署了angular2应用程序,但该应用程序无法定向到子路由。
bitsprint '16

对于IIS(VS 2013中的localhost)的解决方案,我感激不尽。沮丧地将我的头撞了足够长的时间,终于找到了答案。像魅力一样工作。
佛罗里达G.16年

5

正如其他人提到的那样,您需要在服务器上重写路由并设置<base href="https://stackoverflow.com/"/>

对于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()
    ];
  }
  ...
})
....

4

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

errorDocument 404 /index.html

.htaccess可以为我解决此问题。


4

对于Grunt和Browsersync,请在此处使用connect-modrewrite

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 --save2. require in gruntfile3.复制上述服务器obj
Omar

谢谢你,这在带有浏览器同步设置的gulp 4中为我工作。
Abdeali Chandanwala

很高兴它对@Abdeali Chandanwala有所帮助!
MrThunder

@Omar我不同意您的意见,像我这样的不太高级的用户也可以从中了解如何将其添加到gulpfile中。最好记住,人们具有不同的知识水平,仅用gruntfile编写要求不会有帮助,因为我假设他们知道如何将其添加到gulp中。
MrThunder

3

我解决了

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

3

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

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

启用html5Mode时,URL中将不再使用#字符。#符号很有用,因为它不需要服务器端配置。如果没有#,URL看起来会更好,但是它也需要服务器端重写。这里有些例子:

对于使用AngularJS进行Express Rewrites,您可以通过以下更新来解决此问题:

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);
Tigin

2

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

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

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


谢谢您的回答。因此,当我在About页面上并刷新时,服务器应将URL重写为/?问题是我在不同域上使用Rails后端。所有通信均通过API调用进行。我该如何重写这些URL?
Dieter De Mesmaeker

关键是您的应用程序在/的服务器路由上可用,因此当刷新/ about的url时,浏览器将向您的服务器请求/ about的任何页面(在这种情况下,那里没有页面,因此您需要重定向那些回来)。
lucuma

2

我们在Express中进行了服务器重定向:

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

即使添加了,我们仍然遇到页面刷新问题<base href="https://stackoverflow.com/" />

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

:-P


但由于此每个HTTP请求都将具有索引文件,例如:/ getJsonFromServer-一个返回数据的http请求,但由于此配置,它还将返回索引页
vijay

1

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

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

0

我发现了更好的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模块已弃用
Evan Plaice

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

0

我用JHipster生成的Java + angular应用程序也遇到了同样的问题。我用Filter和属性中所有有角页面的列表解决了它:

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

希望对别人有帮助。


0

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() ]
        }
  });
});

0

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

步骤1:下载urlrewritefilter JAR 单击此处 并保存以构建路径WEB-INF / lib

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

步骤3:设定基本网址 <base href="https://stackoverflow.com/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>

步骤5:在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>


0

我有一个我一直在使用的简单解决方案及其作品。

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

0

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

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

注意:刷新页面时,它将查找API而不是Angular页面(因为URL中没有#标记。)。使用上面的代码,我使用#重定向到url


-2

只需在web.config中写出一条规则

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

在索引中添加此

<base href="/">

它对我有用,也许您忘记设置Html5Mode app.config

app.config(function ($stateProvider, $urlRouterProvider, $locationProvider){
    $locationProvider.html5Mode({ enabled: true, requireBase: true });
    $locationProvider.hashPrefix('!');
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.