179

我的印象是 Angular 会重写出现在模板中锚标记的 href 属性中的 URL,这样它们就可以在 html5 模式或 hashbang 模式下工作。位置服务的文档似乎说 HTML 链接重写处理了 hashbang 的情况。因此,我希望当不在 HTML5 模式下时,会插入散列,而在 HTML5 模式下,它们不会。

但是,似乎没有进行重写。以下示例不允许我仅更改模式。应用程序中的所有链接都需要手动重写(或在运行时从变量派生。我是否需要根据模式手动重写所有 URL?

我在 Angular 1.0.6、1.1.4 或 1.1.3 中没有看到任何客户端 url 重写。似乎所有href 值都需要在hashbang 模式和/ html5 模式前面加上#/。

是否需要一些配置来导致重写?我误读了文档吗?做别的傻事?

这是一个小例子:

<head>
    <script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.3/angular.js"></script>
</head>

<body>
    <div ng-view></div>
    <script>
        angular.module('sample', [])
            .config(
        ['$routeProvider', '$locationProvider',
            function ($routeProvider, $locationProvider) {

                //commenting out this line (switching to hashbang mode) breaks the app
                //-- unless # is added to the templates
                $locationProvider.html5Mode(true);

                $routeProvider.when('/', {
                    template: 'this is home. go to <a href="/about"/>about</a>'
                });
                $routeProvider.when('/about', {
                    template: 'this is about. go to <a href="/"/>home</a'
                });
            }
        ])
            .run();
    </script>
</body>

附录:在重新阅读我的问题时,我发现我使用了“重写”这个词,但并没有清楚地说明我想在何时何地进行重写。问题是如何让Angular在呈现路径时重写 URL,以及如何让 Angular 在两种模式下统一解释 JS 代码中的路径。它不是关于如何使 Web 服务器对请求进行与 HTML5 兼容的重写。

4

4 回答 4

361

文档对 AngularJS 路由不是很清楚。它谈到了 Hashbang 和 HTML5 模式。实际上,AngularJS 路由以三种模式运行:

  • 哈希帮模式
  • HTML5 模式
  • HTML5 模式下的 Hashbang

对于每种模式,都有一个各自的 LocationUrl 类(LocationHashbangUrl、LocationUrl 和 LocationHashbangInHTML5Url)。

为了模拟 URL 重写,您必须实际将 html5mode 设置为 true 并按如下方式装饰 $sniffer 类:

$provide.decorator('$sniffer', function($delegate) {
  $delegate.history = false;
  return $delegate;
});

我现在将更详细地解释这一点:

哈希帮模式

配置:

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

当您需要在 HTML 文件中使用带有哈希值的 URL 时,例如在

<a href="index.html#!/path">link</a>

在浏览器中,您必须使用以下链接:http://www.example.com/base/index.html#!/base/path

正如您在纯 Hashbang 模式中看到的那样,HTML 文件中的所有链接都必须以“index.html#!”之类的基础开头。

HTML5 模式

配置:

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

您应该在 HTML 文件中设置基础

<html>
  <head>
    <base href="/">
  </head>
</html>

在这种模式下,您可以在 HTML 文件中使用不带 # 的链接

<a href="/path">link</a>

浏览器中的链接:

http://www.example.com/base/path

HTML5 模式下的 Hashbang

当我们实际使用 HTML5 模式但在不兼容的浏览器中时,会激活此模式。我们可以通过装饰 $sniffer 服务并将历史记录设置为 false 在兼容的浏览器中模拟这种模式。

配置:

$provide.decorator('$sniffer', function($delegate) {
  $delegate.history = false;
  return $delegate;
});
$routeProvider
  .when('/path', {
    templateUrl: 'path.html',
  });
$locationProvider
  .html5Mode(true)
  .hashPrefix('!');

在 HTML 文件中设置基础:

<html>
  <head>
    <base href="/">
  </head>
</html>

在这种情况下,链接也可以在 HTML 文件中不带散列的情况下编写

<a href="/path">link</a>

浏览器中的链接:

http://www.example.com/index.html#!/base/path
于 2013-05-21T19:34:46.200 回答
8

未来的读者,如果您使用的是Angular 1.6,您还需要更改hashPrefix

appModule.config(['$locationProvider', function($locationProvider) {
    $locationProvider.html5Mode(true);
    $locationProvider.hashPrefix('');
}]);

不要忘记在 HTML 中设置基础<head>

<head>
    <base href="/">
    ...
</head>

有关更改日志的更多信息here

于 2017-03-22T08:45:33.580 回答
0

这花了我一段时间才弄清楚,所以这就是我的工作方式 - Angular WebAPI ASP Routing without the # for SEO

  1. 添加到 Index.html - base href="/">
  2. 添加 $locationProvider.html5Mode(true); 到 app.config

  3. 我需要某个控制器(在家庭控制器中)被忽略以上传图像,所以我将该规则添加到 RouteConfig

         routes.MapRoute(
            name: "Default2",
            url: "Home/{*.}",
            defaults: new { controller = "Home", action = "SaveImage" }
        );
    
  4. 在 Global.asax 添加以下内容 - 确保忽略 api 和图像上传路径,让它们正常运行,否则重新路由其他所有内容。

     private const string ROOT_DOCUMENT = "/Index.html";
    
    protected void Application_BeginRequest(Object sender, EventArgs e)
    {
        var path = Request.Url.AbsolutePath;
        var isApi = path.StartsWith("/api", StringComparison.InvariantCultureIgnoreCase);
        var isImageUpload = path.StartsWith("/home", StringComparison.InvariantCultureIgnoreCase);
    
        if (isApi || isImageUpload)
            return;
    
        string url = Request.Url.LocalPath;
        if (!System.IO.File.Exists(Context.Server.MapPath(url)))
            Context.RewritePath(ROOT_DOCUMENT);
    }
    
  5. 确保使用 $location.url('/XXX') 而不是 window.location ... 来重定向

  6. 使用绝对路径引用 CSS 文件

并不是

<link href="app/content/bootstrapwc.css" rel="stylesheet" />

最后一点 - 这样做让我可以完全控制,我不需要对网络配置做任何事情。

希望这会有所帮助,因为这花了我一段时间才弄清楚。

于 2015-11-07T15:15:55.270 回答
0

我希望能够使用 HTML5 模式和固定令牌访问我的应用程序,然后切换到 hashbang 方法(保留令牌以便用户可以刷新他的页面)。

访问我的应用程序的 URL:

http://myapp.com/amazing_url?token=super_token

然后当用户加载页面时:

http://myapp.com/amazing_url?token=super_token#/amazing_url

然后当用户导航时:

http://myapp.com/amazing_url?token=super_token#/another_url

有了这个,我将令牌保留在 URL 中,并在用户浏览时保持状态。我失去了一些 URL 的可见性,但没有完美的方法。

所以不要启用 HTML5 模式,然后添加这个控制器:

.config ($stateProvider)->
    $stateProvider.state('home-loading', {
         url: '/',
         controller: 'homeController'
    })
.controller 'homeController', ($state, $location)->
    if window.location.pathname != '/'
        $location.url(window.location.pathname+window.location.search).replace()
    else
        $state.go('home', {}, { location: 'replace' })
于 2015-10-22T08:53:09.813 回答