$ location / beralih antara html5 dan mode hashbang / penulisan ulang tautan

179

Saya mendapat kesan bahwa Angular akan menulis ulang URL yang muncul dalam atribut href dari tag anchor dalam tempaltes, sehingga mereka akan berfungsi baik dalam mode html5 atau mode hashbang. The dokumentasi untuk layanan lokasi tampaknya mengatakan bahwa HTML link Rewriting mengurus situasi hashbang. Dengan demikian saya berharap bahwa ketika tidak dalam mode HTML5, hash akan dimasukkan, dan dalam mode HTML5, mereka tidak akan melakukannya.

Namun, tampaknya tidak ada penulisan ulang yang terjadi. Contoh berikut tidak memungkinkan saya untuk hanya mengubah mode. Semua tautan dalam aplikasi harus ditulis ulang dengan tangan (atau berasal dari variabel saat runtime. Apakah saya harus menulis ulang semua URL secara manual tergantung pada modenya?

Saya tidak melihat penulisan ulang sisi klien terjadi di Angular 1.0.6, 1.1.4 atau 1.1.3. Tampaknya semua nilai href perlu diawali dengan # / untuk mode hashbang dan / untuk mode html5.

Apakah ada beberapa konfigurasi yang diperlukan untuk menyebabkan penulisan ulang? Apakah saya salah membaca dokumen? Melakukan hal lain yang konyol?

Ini sebuah contoh kecil:

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

Tambahan: dalam membaca kembali pertanyaan saya, saya melihat bahwa saya menggunakan istilah "menulis ulang" tanpa banyak kejelasan tentang siapa dan kapan saya ingin melakukan penulisan ulang. Pertanyaannya adalah tentang bagaimana cara mendapatkan Angular untuk menulis ulang URL ketika itu membuat jalur dan bagaimana mendapatkannya untuk menafsirkan jalur dalam kode JS secara seragam di kedua mode. Ini bukan tentang bagaimana menyebabkan server web melakukan penulisan ulang permintaan yang kompatibel dengan HTML5.

laurelnaiad
sumber
1
Ini solusi untuk Angular 1.6 .
Mistalis

Jawaban:

361

Dokumentasi tidak begitu jelas tentang perutean AngularJS. Ini berbicara tentang mode Hashbang dan HTML5. Bahkan, perutean AngularJS beroperasi dalam tiga mode:

  • Mode Hashbang
  • Mode HTML5
  • Hashbang dalam Mode HTML5

Untuk setiap mode ada kelas LocationUrl masing-masing (LocationHashbangUrl, LocationUrl dan LocationHashbangInHTML5Url).

Untuk mensimulasikan penulisan ulang URL, Anda harus benar-benar mengatur html5mode menjadi true dan menghias kelas $ sniffer sebagai berikut:

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

Sekarang saya akan menjelaskan ini secara lebih rinci:

Mode Hashbang

Konfigurasi:

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

Ini adalah kasus ketika Anda perlu menggunakan URL dengan hash di file HTML Anda seperti di

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

Di Peramban Anda harus menggunakan Tautan berikut: http://www.example.com/base/index.html#!/base/path

Seperti yang dapat Anda lihat dalam mode Hashbang murni, semua tautan dalam file HTML harus dimulai dengan basis seperti "index.html #!".

Mode HTML5

Konfigurasi:

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

Anda harus mengatur basis dalam file HTML

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

Dalam mode ini Anda dapat menggunakan tautan tanpa # dalam file HTML

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

Tautan di Browser:

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

Hashbang dalam Mode HTML5

Mode ini diaktifkan ketika kami benar-benar menggunakan mode HTML5 tetapi di browser yang tidak kompatibel. Kita dapat mensimulasikan mode ini di browser yang kompatibel dengan mendekorasi layanan $ sniffer dan mengatur histori menjadi false.

Konfigurasi:

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

Atur basis dalam file HTML:

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

Dalam hal ini tautan juga dapat ditulis tanpa hash dalam file HTML

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

Tautan di Browser:

http://www.example.com/index.html#!/base/path
Jupiter
sumber
Terima kasih atas penjelasan terperinci, @jupiter. Saya akan melihat apakah saya bisa melewatkan bang dan menjaga hash dan menipu Angular agar tidak memerlukan dua set URL tergantung pada modenya!
laurelnaiad
1
Saya pikir saya belum memahami dengan baik masalah Anda. Mengapa Anda tidak menggunakan URL saja tanpa hash? Mereka akan bekerja di browser yang mendukung API riwayat dan browser yang tidak mendukung API riwayat. AngularJS akan menempatkan versi # ke dalam bilah lokasi ketika Anda mengekliknya di browser yang tidak mendukung API riwayat karena AngularJS memotong klik pada tautan.
jupiter
Saya sedang mengerjakan kerangka kerja yang harus mendukung kedua mode. Penulis aplikasi harus dapat memilih satu atau yang lain tanpa khawatir tentang apakah ada hash dalam templat mereka dan / atau perubahan dalam interpretasi jalur relatif. Saya berharap trik Anda akan membantu menjadikannya benar bahwa "yang Anda lakukan hanyalah mengubah mode" (bahkan jika solusi praktisnya adalah "setel mode ke html5 dan kemudian bohongi tentang kemampuan browser").
laurelnaiad
1
Saya mendapatkan $providetidak terdefinisi?
Petrus Theron
1
@pate - Anda harus menyuntikkan $ menyediakan dalam fungsi konfigurasi Anda saat Anda mengatur dekorator.
laurelnaiad
8

Bagi pembaca masa depan, jika Anda menggunakan Angular 1.6 , Anda juga perlu mengubah hashPrefix:

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

Jangan lupa untuk mengatur basis di HTML Anda <head>:

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

Info lebih lanjut tentang changelog here.

Mistalis
sumber
3
terima kasih @Mistalis. jawaban Anda bekerja dengan baik. tetapi masalah ketika saya me-refresh halaman setelah perutean, halaman tidak ditemukan kesalahan terjadi. tolong bantu saya ..
Ashish Mehta
@AshishMehta Halo Ashish. Saya sarankan Anda untuk membaca jawaban ini , ini dapat menyelesaikan masalah Anda. Sampai jumpa! :)
Mistalis
0

Ini membutuhkan waktu beberapa saat untuk mencari tahu, jadi inilah cara saya membuatnya berfungsi - Angular WebAPI ASP Routing tanpa # untuk SEO

  1. tambahkan ke Index.html - basis href = "/">
  2. Tambahkan $ locationProvider.html5Mode (true); ke app.config

  3. Saya membutuhkan pengontrol tertentu (yang ada di pengontrol rumah) untuk diabaikan untuk mengunggah gambar jadi saya menambahkan aturan itu ke RouteConfig

         routes.MapRoute(
            name: "Default2",
            url: "Home/{*.}",
            defaults: new { controller = "Home", action = "SaveImage" }
        );
  4. Di Global.asax tambahkan yang berikut - pastikan untuk mengabaikan api dan jalur unggah gambar biarkan mereka berfungsi seperti biasa jika tidak mengalihkan semua yang lain.

     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. Pastikan untuk menggunakan $ location.url ('/ XXX') dan bukan window.location ... untuk mengarahkan ulang

  6. Referensi file CSS dengan jalur absolut

dan tidak

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

Catatan akhir - melakukannya dengan cara ini memberi saya kontrol penuh dan saya tidak perlu melakukan apa pun pada konfigurasi web.

Semoga ini bisa membantu karena ini perlu waktu untuk mencari tahu.

tfa
sumber
0

Saya ingin dapat mengakses aplikasi saya dengan mode HTML5 dan token tetap dan kemudian beralih ke metode hashbang (untuk menjaga token sehingga pengguna dapat menyegarkan halamannya).

URL untuk mengakses aplikasi saya:

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

Lalu ketika pengguna memuat halaman:

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

Lalu ketika pengguna menavigasi:

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

Dengan ini saya menyimpan token di URL dan mempertahankan status saat pengguna menjelajah. Saya kehilangan sedikit visibilitas URL, tetapi tidak ada cara yang sempurna untuk melakukannya.

Jadi jangan aktifkan mode HTML5 dan kemudian tambahkan controller ini:

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