web-dev-qa-db-fra.com

$ emplacement / commutation entre le mode html5 et hashbang / réécriture de liens

J'avais l'impression que Angular réécrirait les URL apparaissant dans les attributs href des balises d'ancrage au sein de tempaltes, de sorte qu'elles fonctionneraient en mode html5 ou en mode hashbang. Le documentation pour le service de localisation semble indiquer que la réécriture de liens HTML prend en charge la situation de hashbang. Je m'attendrais donc à ce que les hachages ne soient pas insérés en mode HTML5, mais pas en mode HTML5.

Cependant, il semble qu'aucune réécriture n'ait lieu. L'exemple suivant ne me permet pas de changer de mode. Tous les liens de l'application doivent être réécrits manuellement (ou dérivés d'une variable au moment de l'exécution. Suis-je obligé de réécrire manuellement toutes les URL en fonction du mode?

Je ne vois pas de réécriture d'URL côté client en cours dans Angular 1.0.6, 1.1.4 ou 1.1.3. Il semble que toutes les valeurs href doivent être précédées de #/pour le mode hashbang et/pour le mode html5.

Une configuration est-elle nécessaire pour provoquer la réécriture? Est-ce que je me trompe dans la documentation? Faire autre chose d'idiot?

Voici un petit exemple:

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

Additif: en relisant ma question, je vois que j’ai utilisé le terme "réécriture" sans préciser le nom de qui et quand je voulais faire la réécriture. La question est de savoir comment obtenir Angular de réécrire les URL lors du rendu des chemins et comment le faire pour interpréter les chemins dans le code JS de manière uniforme entre les deux modes. Il ne s'agit pas de faire en sorte qu'un serveur Web procède à la réécriture des demandes compatible avec HTML5.

178
laurelnaiad

La documentation n'est pas très claire sur le routage AngularJS. Il parle de Hashbang et du mode HTML5. En fait, le routage AngularJS fonctionne selon trois modes:

  • Mode Hashbang
  • Mode HTML5
  • Hashbang en mode HTML5

Pour chaque mode, il existe une classe LocationUrl respective (LocationHashbangUrl, LocationUrl et LocationHashbangInHTML5Url).

Pour simuler la réécriture d'URL, vous devez en réalité définir html5mode sur true et décorer la classe $ sniffer comme suit:

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

Je vais maintenant expliquer cela plus en détail:

Mode Hashbang

Configuration:

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

C’est le cas lorsque vous devez utiliser des URL avec des hachages dans vos fichiers HTML, comme dans

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

Dans le navigateur, vous devez utiliser le lien suivant: http://www.example.com/base/index.html#!/base/path

Comme vous pouvez le voir en mode Hashbang pur, tous les liens dans les fichiers HTML doivent commencer par la base, tels que "index.html #!".

Mode HTML5

Configuration:

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

Vous devez définir la base en fichier HTML

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

Dans ce mode, vous pouvez utiliser des liens sans le # dans les fichiers HTML.

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

Lien dans le navigateur:

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

Hashbang en mode HTML5

Ce mode est activé lorsque nous utilisons le mode HTML5, mais dans un navigateur incompatible. Nous pouvons simuler ce mode dans un navigateur compatible en décorant le service $ sniffer et en définissant l'historique sur false.

Configuration:

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

Définissez la base en fichier HTML:

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

Dans ce cas, les liens peuvent également être écrits sans le hachage dans le fichier HTML

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

Lien dans le navigateur:

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

Pour les futurs lecteurs, si vous utilisez Angular 1.6 , vous devez également modifier la hashPrefix:

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

N'oubliez pas de définir la base dans votre code HTML <head>:

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

Plus d'infos sur le changelog here.

7
Mistalis

Je souhaitais pouvoir accéder à mon application avec le mode HTML5 et un jeton fixe, puis passer à la méthode hashbang (conserver le jeton afin que l'utilisateur puisse actualiser sa page).

URL pour accéder à mon application:

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

Puis lorsque l'utilisateur charge la page:

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

Puis lorsque l'utilisateur navigue:

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

Avec cela, je conserve le jeton dans l'URL et conserve l'état lorsque l'utilisateur navigue. J'ai perdu un peu de visibilité sur l'URL, mais il n'y a pas de façon parfaite de le faire.

Donc, n'activez pas le mode HTML5 et ajoutez ensuite ce contrôleur:

.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' })
0
Luc Boissaye

Cela m’a pris un certain temps à comprendre, c’est ainsi que j’ai fonctionné - Angular WebAPI ASP Routage sans le # pour le référencement

  1. ajouter à Index.html - base href = "/">
  2. Ajouter $ locationProvider.html5Mode (true); à app.config

  3. J'avais besoin d'un certain contrôleur (qui se trouvait dans le contrôleur domestique) pour être ignoré lors du téléchargement d'images. J'ai donc ajouté cette règle à RouteConfig.

         routes.MapRoute(
            name: "Default2",
            url: "Home/{*.}",
            defaults: new { controller = "Home", action = "SaveImage" }
        );
    
  4. Dans Global.asax, ajoutez ce qui suit: assurez-vous d'ignorer les chemins d'accès à l'API et aux images, laissez-les fonctionner normalement, sinon redéfinissez tout le reste.

     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. Assurez-vous d'utiliser $ location.url ('/ XXX') et pas window.location ... pour rediriger

  6. Référencez les fichiers CSS avec un chemin absolu

et pas

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

Note finale - le faire de cette façon m'a permis un contrôle total et je n'ai rien eu à faire avec la configuration Web.

J'espère que cela aide car cela m'a pris un certain temps à comprendre.

0
tfa