Angular1.0路由的Hashbang和HTML5模式

原文答主jupiter

http://stackoverflow.com/questions/16677528/location-switching-between-html5-and-hashbang-mode-link-rewritingdown vote

The documentation is not very clear about AngularJS routing. It talks about Hashbang and HTML5 mode. In fact, AngularJS routing operates in three modes:

  1. Hashbang Mode
  2. HTML5 Mode
  3. Hashbang in HTML5 Mode

For each mode there is a a respective LocationUrl class (LocationHashbangUrl, LocationUrl and LocationHashbangInHTML5Url).

In order to simulate URL rewriting you must actually set html5mode to true and decorate the $sniffer class as follows:

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

I will now explain this in more detail:

Hashbang Mode

Configuration:

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


This is the case when you need to use URLs with hashes in your HTML files such as in

<a href="index.html#!/path">link</a>
In the Browser you must use the following Link: http://www.example.com/base/index.html#!/base/path

As you can see in pure Hashbang mode all links in the HTML files must begin with the base such as "index.html#!".

HTML5 Mode

Configuration:

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


You should set the base in HTML-file

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


In this mode you can use links without the # in HTML files

<a href="/path">link</a>
Link in Browser:

http://www.example.com/base/path
Hashbang in HTML5 Mode

This mode is activated when we actually use HTML5 mode but in an incompatible browser. We can simulate this mode in a compatible browser by decorating the $sniffer service and setting history to false.

Configuration:

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


Set the base in HTML-file:

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


In this case the links can also be written without the hash in the HTML file

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


Link in Browser:

http://www.example.com/index.html#!/base/path

使用最后一种, html内用{{linkPrefix}} 等于'/', 结果自动在/后面加上!#并且能回退自如,直接访问地址栏

(function () {

  'use strict';

  var appConfig = function ($routeProvider, jwtInterceptorProvider, $httpProvider, $locationProvider,$provide) {
    $routeProvider.otherwise('/404');

    //jwtInterceptorProvider.tokenGetter = function (store) {
    //  return store.get('jwt');

//可以使用多个decorator
          $provide.decorator('$locale', function ($delegate) {
              var value = $delegate.DATETIME_FORMATS;

              value.SHORTDAY = [
                  "",
                  "",
                  "",
                  "",
                  "",
                  "",
                  ""
              ];

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


    $httpProvider.interceptors.push('jwtInterceptor');
    $httpProvider.interceptors.push('TokenInterceptor');




      $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';


      $locationProvider.html5Mode({ enabled: true, requireBase: false, rewriteLinks: true }); 
      $locationProvider.hashPrefix('!');  
    };

  appConfig.$inject = ['$routeProvider', 'jwtInterceptorProvider', '$httpProvider', '$locationProvider','$provide'];

  var appRun = function ($rootScope,$window, $location, jwtHelper,$translate, AuthService, $sessionStorage,deviceDetector) {

      $rootScope.isMobile="is_mobile";
      $rootScope.screenWidth=$window.innerWidth;
      if  ((deviceDetector.os==="android"||deviceDetector.os==="ios" ||deviceDetector.os==="windows-phone"||deviceDetector.device==="blackberry")&& $rootScope.screenWidth<768)
          $rootScope.isMobile=true;
        else $rootScope.isMobile=false;


    // Store user data in $rootScope.account if user is logged in
    if ($sessionStorage.jwt && !jwtHelper.isTokenExpired($sessionStorage.jwt)) {
      var jwt = $sessionStorage.jwt;
      $rootScope.account = jwt && jwtHelper.decodeToken(jwt);

    }



    $rootScope.$on('$routeChangeStart', function (e, to) {
      if (to.data) {
        if (to.data.requiresLogin) {
          // Stop users from getting to routes that have value requiresLogin set on true
          if (!$sessionStorage.jwt || jwtHelper.isTokenExpired($sessionStorage.jwt)) {
            e.preventDefault();
              $translate("Token Expired.").then(function(value){

                      $rootScope.tokenExpired=value;
                      $window.alert($rootScope.tokenExpired);
                  }
              );


            $location.path('/');
          }
        } else {
          // Stop users from getting to routes that have value requiresLogin set on false
          if ($sessionStorage.jwt && !jwtHelper.isTokenExpired($sessionStorage.jwt)) {
            e.preventDefault();
            $location.path(AuthService.getLoginRedirectUrl());
          }
        }
      }
    });



  };

  appRun.$inject = ['$rootScope', '$window','$location', 'jwtHelper','$translate', 'AuthService', '$sessionStorage','deviceDetector'];

  angular
    .module('warrantyProcessApp', [
      'ngRoute',
      ... ...

    ])
    .config(appConfig)
    .run(appRun);

})();
例子

 不过我得到的路径是http://www.example.com/#!/base/path

访问根目录是http://www.example.com/#!/ ( 后面的/#!/都是访问时自动rewirte 到地址栏的 )

twitter和17startup的地址url中都有#!,被称为pretty ajax url 
 
 
如果说是地址重写或者是restful风格为什么要用#!这么奇怪的地址呢?
以下内容截取自顾轶灵的回答:

传统jQuery方法:

利用 HTML5 history session management 作为历史记录:

This way you don't have to use hashes in newer browsers and that way the user won't notice a thing.

function route(path) {
    $.get(path, function(data) {
        //parse data
    });
}

if (typeof history.pushState !== 'undefined') 
{
    $(window).bind('popstate', function(e)
    {
        route(window.location.pathname);
    });
    $('a').click(function(event) {
        event.preventDefault();
        history.pushState({},'',this.href);
    });
} else {
    $(window).bind('hashchange', function(e)
    {
        route(window.location.hash);
    });
    $('a').click(function(event) {
        event.preventDefault();
        $(this).attr('href', '/#'+$(this).attr('href'));
    });
}

 延伸阅读:

angular 路由去除#号

http://www.cnblogs.com/breakdown/p/3785773.html

原文地址:https://www.cnblogs.com/haimingpro/p/6399748.html