$ location / переключение между html5 и режимом hashbang / перезапись ссылок

179

У меня сложилось впечатление, что Angular переписывает URL-адреса, которые появляются в атрибутах href тегов привязки внутри шаблонов, так что они будут работать либо в режиме html5, либо в режиме hashbang. Документация на услуги определения местоположения , кажется, говорят , что HTML Link Rewriting заботится о ситуации hashbang. Таким образом, я ожидаю, что когда не в режиме HTML5, будут вставлены хэши, а в режиме HTML5 - нет.

Тем не менее, кажется, что переписывание не происходит. Следующий пример не позволяет мне просто изменить режим. Все ссылки в приложении должны быть переписаны вручную (или получены из переменной во время выполнения. Требуется ли вручную переписывать все URL-адреса в зависимости от режима?

Я не вижу переписывания URL на стороне клиента в Angular 1.0.6, 1.1.4 или 1.1.3. Кажется, что все значения 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="https://stackoverflow.com/about"/>about</a>'
                });
                $routeProvider.when('/about', {
                    template: 'this is about. go to <a href="https://stackoverflow.com/"/>home</a'
                });
            }
        ])
            .run();
    </script>
</body>

Приложение: перечитывая мой вопрос, я вижу, что использовал термин «переписывание» без излишней ясности в отношении того, кто и когда хотел переписать. Вопрос заключается в том, как заставить Angular переписывать URL-адреса при рендеринге путей, и как заставить его интерпретировать пути в коде JS равномерно в двух режимах. Речь идет не о том, как заставить веб-сервер выполнять совместимое с HTML5 переписывание запросов.

laurelnaiad
источник
1
Вот решение для Angular 1.6 .
Мисталис

Ответы:

361

В документации не очень ясно про маршрутизацию AngularJS. Это говорит о Hashbang и режиме HTML5. Фактически, маршрутизация AngularJS работает в трех режимах:

  • Hashbang Mode
  • Режим HTML5
  • Hashbang в режиме HTML5

Для каждого режима существует соответствующий класс LocationUrl (LocationHashbangUrl, LocationUrl и LocationHashbangInHTML5Url).

Чтобы смоделировать перезапись URL-адреса, вы должны установить для html5mode значение true и украсить класс $ sniffer следующим образом:

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

Теперь я объясню это более подробно:

Hashbang Mode

Конфигурация:

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

Это тот случай, когда вам нужно использовать URL-адреса с хэшами в ваших HTML-файлах, например, в

<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

Hashbang в режиме HTML5

Этот режим активируется, когда мы фактически используем режим 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
Юпитер
источник
Спасибо за подробное объяснение, @jupiter. Я посмотрю, смогу ли я пропустить взрыв и сохранить хэш и трюк Angular, чтобы в зависимости от режима не требовалось два набора URL-адресов!
Laurelnaiad
1
Я думаю, что я не правильно понял вашу проблему. Почему бы вам не использовать только URL без хэша? Они будут работать в браузерах, поддерживающих API истории, и браузерах, не поддерживающих API истории. AngularJS помещает версию # в строку адреса, когда вы нажимаете на них в браузерах, не поддерживающих API истории, так как AngularJS перехватывает щелчки по ссылкам.
Юпитер
Я работаю над фреймворком, который должен поддерживать оба режима. Авторы приложений должны иметь возможность выбирать одно или другое, не беспокоясь о том, есть ли в их шаблонах хеши и / или изменения в интерпретации относительных путей. Я надеюсь, что ваш трюк поможет сделать так, что «все, что вы делаете, это меняете режим» (даже если практическим решением будет «установить режим на html5, а затем обмануть возможности браузера»).
Laurelnaiad
1
Я получаю $provideне определено?
Петрус Терон
1
@pate - при настройке декоратора вам нужно ввести $ обеспечить в функцию конфигурации.
Laurelnaiad
8

Будущие читатели, если вы используете Angular 1.6 , вам также необходимо изменить hashPrefix:

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

Не забудьте установить базу в своем HTML <head>:

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

Подробнее о журнале изменений here.

Mistalis
источник
3
спасибо @Mistalis. твой ответ работает нормально. но проблема, когда я обновляю страницу после маршрутизации, возникает ошибка "страница не найдена". пожалуйста, помогите мне ..
Ашиш Мехта
@AshishMehta Привет, Ашиш. Я предлагаю вам прочитать этот ответ , он может решить вашу проблему. До свидания! :)
Mistalis
0

Мне потребовалось некоторое время, чтобы понять, как это работает - Angular WebAPI ASP Routing без # для 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" />

Заключительное замечание - выполнение этого способа дало мне полный контроль, и мне не нужно было ничего делать с веб-конфигурацией.

Надеюсь, это поможет, так как мне понадобилось время, чтобы понять.

TFA
источник
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' })
Люк Буассай
источник