$ location/переключение между html5 и режимом hashbang/переписывание ссылок
У меня создалось впечатление, что Angular будет переписывать URL-адреса, которые появляются в атрибутах href тегов привязки в tempaltes, так что они будут работать в режиме html5 или режиме hashbang. Документация для службы определения местоположения, похоже, говорит о том, что переписывание HTML Link заботится о ситуации хеш-бэнга. Поэтому я ожидал бы, что когда не в режиме 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="/about"/>about</a>'
});
$routeProvider.when('/about', {
template: 'this is about. go to <a href="/"/>home</a'
});
}
])
.run();
</script>
</body>
Приложение: при повторном чтении моего вопроса я вижу, что я использовал термин "переписывание" без обилия ясности относительно того, кто и когда я хотел сделать переписывание. Вопрос заключается в том, как получить Angular, чтобы переписать URL-адреса, когда он отображает пути, и как заставить его интерпретировать пути в JS-коде равномерно в двух режимах. Это не о том, как заставить веб-сервер выполнять HTML5-совместимую переписывание запросов.
Ответы
Ответ 1
В документации не очень понятно о маршрутизации AngularJS. В нем говорится о режиме Hashbang и HTML5. Фактически, маршрутизация AngularJS работает в трех режимах:
- Режим Hashbang
- Режим HTML5
- Hashbang в режиме HTML5
Для каждого режима есть соответствующий класс LocationUrl (LocationHashbangUrl, LocationUrl и LocationHashbangInHTML5Url).
Чтобы смоделировать переписывание URL, вы должны фактически установить html5mode в true и украсить класс $сниффера следующим образом:
$provide.decorator('$sniffer', function($delegate) {
$delegate.history = false;
return $delegate;
});
Теперь я объясню это более подробно:
Режим Hashbang
Конфигурация:
$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
Как вы можете видеть в режиме чистого хашбанга, все ссылки в файлах 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
Этот режим активируется, когда мы действительно используем режим 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
Ответ 2
Вперед, если вы используете Angular 1.6, вам также нужно изменить hashPrefix
:
appModule.config(['$locationProvider', function($locationProvider) {
$locationProvider.html5Mode(true);
$locationProvider.hashPrefix('');
}]);
Не забудьте установить базу в своем HTML <head>
:
<head>
<base href="/">
...
</head>
Подробнее о changelog здесь.
Ответ 3
Я хотел иметь доступ к моему приложению с режимом 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' })
Ответ 4
Мне потребовалось некоторое время, чтобы разобраться, так вот как я его работаю - Angular WebAPI ASP Routing без # для SEO
- добавить в Index.html - base href= "/" >
-
Добавить $locationProvider.html5Mode (true); к app.config
-
Мне нужен какой-то контроллер (который был в домашнем контроллере) для игнорирования для загрузки изображений, поэтому я добавил это правило в RouteConfig
routes.MapRoute(
name: "Default2",
url: "Home/{*.}",
defaults: new { controller = "Home", action = "SaveImage" }
);
-
В 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);
}
-
Обязательно используйте $location.url('/XXX'), а не window.location... для перенаправления
-
Ссылка на файлы CSS с абсолютным путем
а не
<link href="app/content/bootstrapwc.css" rel="stylesheet" />
Заключительная записка - это так дало мне полный контроль, и мне не нужно было ничего делать с веб-конфигурацией.
Надеюсь, это поможет, так как мне понадобилось время, чтобы понять.