Định tuyến AngularJS không có hàm băm '#'


223

Tôi đang học AngularJS và có một điều thực sự làm tôi khó chịu.

Tôi sử dụng $routeProviderđể khai báo các quy tắc định tuyến cho ứng dụng của mình:

$routeProvider.when('/test', {
  controller: TestCtrl,
  templateUrl: 'views/test.html'
})
.otherwise({ redirectTo: '/test' });

nhưng khi tôi điều hướng đến ứng dụng của mình trong trình duyệt thì tôi thấy app/#/testthay vì app/test.

Vì vậy, câu hỏi của tôi là tại sao AngularJS thêm băm này #vào url? Có khả năng nào để tránh nó không?


2
Đây là giải pháp nếu bạn đang sử dụng Angular 1.6.
Mistalis

Câu trả lời:


265

Trong thực tế, bạn cần # (hashtag) cho các trình duyệt không phải là HTML5.

Nếu không, họ sẽ thực hiện một cuộc gọi HTTP đến máy chủ tại địa chỉ được đề cập. # Là một shortcircuit trình duyệt cũ không thực hiện yêu cầu, cho phép nhiều khung js xây dựng định tuyến khách hàng của riêng họ trên đầu trang.

Bạn có thể sử dụng $locationProvider.html5Mode(true)để nói với góc cạnh để sử dụng chiến lược HTML5 nếu có.

Dưới đây là danh sách các trình duyệt hỗ trợ chiến lược HTML5: http://caniuse.com/#feat=history


4
OK, cảm ơn bạn. Đây là điều mà tôi nghi ngờ. Nhưng đối với tôi điều này là khá thân thiện với người dùng! Giả sử tôi muốn một số tài nguyên có sẵn thông qua url, ứng dụng / res. Làm cách nào để người dùng trang web của tôi phát hiện ra rằng họ nên nhập ứng dụng / # / res thay thế?
pikkvile

5
Nhưng nếu vậy, tại sao tôi cần những đường dẫn này hiển thị trên thanh vị trí? Nếu người dùng sẽ không sử dụng chúng, tôi chỉ có thể tạo ứng dụng javascript một trang.
pikkvile

6
Thật hữu ích khi bạn muốn theo dõi trạng thái ứng dụng. Các khuôn khổ cung cấp một cơ chế lịch sử. Ngoài ra, nó cho phép truy cập trực tiếp trạng thái ứng dụng của bạn thông qua chia sẻ url
:

6
Không cần hashtag trong các trình duyệt hiện đại hỗ trợ API lịch sử HTML5. Xem câu trả lời của @ skeep và các liên kết được cung cấp. Trong chế độ HTML5, Angular sẽ chỉ sử dụng hashtags nếu trình duyệt không hỗ trợ. Cũng lưu ý rằng, bạn không phải sử dụng $ routeProvider nếu bạn không muốn ... bạn có thể kết nối định tuyến của riêng mình bằng cách sử dụng ng-click và ng-gộp (thực sự bạn phải làm điều này nếu bạn cần nhiều cấp độ định tuyến, vì ng-view chỉ có thể xuất hiện một lần trên mỗi trang). Xem thêm stackoverflow.com/questions/12793609/
Mark Rajcok

2
Đối với trường hợp html hiển thị phía băm / Pushstate / phía máy chủ, Twitter rất đẹp để đọc Engineering.twitter.com/2012/12/. Nó giải thích cách họ quản lý để làm điều đó sao cho tương thích ngược với trình duyệt cũ và với tìm kiếm động cơ. Tôi biết nó không phải là angularjs cụ thể nhưng bạn có thể tái tạo dòng chảy.
jackdbernier

47

Nếu bạn đã bật html5mode như những người khác đã nói và tạo một .htaccesstệp có nội dung sau (điều chỉnh theo nhu cầu của bạn):

RewriteEngine   On
RewriteBase     /
RewriteCond     %{REQUEST_URI} !^(/index\.php|/img|/js|/css|/robots\.txt|/favicon\.ico)
RewriteCond     %{REQUEST_FILENAME} !-f
RewriteCond     %{REQUEST_FILENAME} !-d
RewriteRule     ./index.html [L]

Người dùng sẽ được chuyển đến ứng dụng của bạn khi họ nhập một tuyến thích hợp và ứng dụng của bạn sẽ đọc tuyến đường đó và đưa họ đến đúng "trang" bên trong nó.

EDIT: Chỉ cần đảm bảo không có bất kỳ tên tệp hoặc thư mục nào xung đột với các tuyến đường của bạn.


Có phiên bản nginx này không? khi tôi tải /abouttrang không thành công trừ khi tôi truy cập nó thông qua ứng dụng.
chovy

Không bao giờ sử dụng chúng, nhưng hãy thử điều này: stackoverflow.com/questions/5840497/convert-htaccess-to-nginx
gái

3
@chovy - ở đây có phiên bản nGinx: server {server_name my-app; root / đường dẫn / đến / ứng dụng; vị trí / {try_files $ uri $ uri / /index.html; }}
Moin Haidar

4
nhớ <base href = "/"> </ base> trong thẻ head
Silvio Troia

Cảm ơn! không có điều này, liên kết sâu là không thể. Tôi vẫn không chắc chắn rằng tính đẹp hay URI đáng để duy trì sự cố này nếu bạn cần liên kết sâu, đặc biệt là trong một số môi trường đám mây / paas nơi bạn có thể không dễ dàng truy cập vào cấu hình httpd.
Pierre Henry

39

Hãy viết câu trả lời có vẻ đơn giản và ngắn gọn

Trong Bộ định tuyến ở cuối, thêm html5Mode (true) ;

app.config(function($routeProvider,$locationProvider) {

    $routeProvider.when('/home', {
        templateUrl:'/html/home.html'
    });

    $locationProvider.html5Mode(true);
})

Trong đầu html thêm thẻ cơ sở

<html>
<head>
    <meta charset="utf-8">    
    <base href="/">
</head>

cảm ơn @plus - đã trình bày chi tiết câu trả lời trên


Tôi đã không thể làm cho điều này để làm việc. Tôi đã đăng một câu hỏi mới với các chi tiết cụ thể của tôi tại: stackoverflow.com/questions/36041074/ Khăn Xin hãy nhìn vào câu hỏi này và nếu bạn có thể giúp tôi sẽ đánh giá rất cao nó.
Larry Martell


12

Thông tin sau đây là từ:
https://scotch.io/quick-tips/pretty-urls-in-angularjs-removing-the-hashtag

Rất dễ dàng để có được các URL sạch và xóa hashtag khỏi URL trong Angular.
Theo mặc định, AngularJS sẽ định tuyến URL bằng hashtag Ví dụ:

Có 2 điều cần phải làm.

  • Định cấu hình $ locationProvider

  • Đặt cơ sở của chúng tôi cho các liên kết tương đối

  • $ dịch vụ định vị

Trong Angular, dịch vụ $ location phân tích URL trong thanh địa chỉ và thực hiện các thay đổi cho ứng dụng của bạn và ngược lại.

Tôi đặc biệt khuyên bạn nên đọc qua các tài liệu vị trí chính thức của Angular $ để cảm nhận về dịch vụ định vị và những gì nó cung cấp.

https://docs.angularjs.org/api/ng/service/$location

$ locationProvider và html5Mode

  • Chúng tôi sẽ sử dụng mô đun $ locationProvider và đặt html5Mode thành true.
  • Chúng tôi sẽ làm điều này khi xác định ứng dụng Angular của bạn và định cấu hình các tuyến đường của bạn.

    angular.module('noHash', [])
    
    .config(function($routeProvider, $locationProvider) {
    
       $routeProvider
           .when('/', {
               templateUrl : 'partials/home.html',
               controller : mainController
           })
           .when('/about', {
               templateUrl : 'partials/about.html',
               controller : mainController
           })
           .when('/contact', {
               templateUrl : 'partials/contact.html',
               controller : mainController
           });
    
       // use the HTML5 History API
       $locationProvider.html5Mode(true); });

API lịch sử HTML5 là gì? Đó là một cách chuẩn hóa để thao tác lịch sử trình duyệt bằng cách sử dụng tập lệnh. Điều này cho phép Angular thay đổi định tuyến và URL của các trang của chúng tôi mà không cần làm mới trang. Để biết thêm thông tin về điều này, đây là một Bài viết API Lịch sử HTML5 tốt:

http://diveintohtml5.info/history.html

Cài đặt cho các liên kết tương đối

  • Để liên kết xung quanh ứng dụng của bạn bằng các liên kết tương đối, bạn sẽ cần đặt <base>trong <head>tài liệu của mình. Điều này có thể nằm trong tệp index.html gốc của ứng dụng Angular của bạn. Tìm <base>thẻ và đặt nó vào URL gốc bạn muốn cho ứng dụng của mình.

Ví dụ: <base href="https://stackoverflow.com/">

  • Có rất nhiều cách khác để định cấu hình này và chế độ HTML5 được đặt thành true sẽ tự động giải quyết các liên kết tương đối. Nếu gốc ứng dụng của bạn khác với url (ví dụ / my-base, thì hãy sử dụng nó làm cơ sở của bạn.

Dự phòng cho các trình duyệt cũ hơn

  • Dịch vụ $ location sẽ tự động chuyển sang phương thức hashbang cho các trình duyệt không hỗ trợ API Lịch sử HTML5.
  • Điều này xảy ra trong suốt với bạn và bạn sẽ không phải cấu hình bất cứ điều gì để nó hoạt động. Từ các tài liệu vị trí $ Angular, bạn có thể thấy phương thức dự phòng và cách thức hoạt động của nó.

Tóm lại là

  • Đây là một cách đơn giản để có được các URL đẹp và xóa hashtag trong ứng dụng Angular của bạn. Hãy vui vẻ làm cho những ứng dụng Angular siêu sạch và siêu nhanh!

3

Nếu bạn muốn định cấu hình cục bộ này trên OS X 10.8 phục vụ Angular với Apache thì bạn có thể tìm thấy những điều sau trong tệp .htaccess của mình giúp:

<IfModule mod_rewrite.c>
    Options +FollowSymlinks
    RewriteEngine On
    RewriteBase /~yourusername/appname/public/
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} !.*\.(css|js|html|png|jpg|jpeg|gif|txt)
    RewriteRule (.*) index.html [L]
</IfModule>

Tùy chọn + FollowSymlinks nếu không được đặt có thể cung cấp cho bạn một lỗi bị cấm trong nhật ký như vậy:

Options FollowSymLinks or SymLinksIfOwnerMatch is off which implies that RewriteRule directive is forbidden

Cơ sở Rewrite là bắt buộc nếu không các yêu cầu sẽ được giải quyết đến root máy chủ của bạn, theo mặc định, đó không phải là thư mục dự án của bạn trừ khi bạn đã cấu hình cụ thể vhost của mình, vì vậy bạn cần đặt đường dẫn để yêu cầu tìm thấy thư mục gốc của dự án. Ví dụ trên máy của tôi, tôi có thư mục / Users / me / Sites nơi tôi giữ tất cả các dự án của mình. Giống như OS X cũ được thiết lập.

Hai dòng tiếp theo nói một cách hiệu quả nếu đường dẫn không phải là thư mục hoặc tệp, vì vậy bạn cần đảm bảo rằng bạn không có tệp hoặc thư mục giống như đường dẫn tuyến ứng dụng của bạn.

Điều kiện tiếp theo cho biết nếu yêu cầu không kết thúc bằng phần mở rộng tệp được chỉ định, hãy thêm những gì bạn cần vào đó

Và [L] cuối cùng đang nói để phục vụ tệp index.html - ứng dụng của bạn cho tất cả các yêu cầu khác.

Nếu bạn vẫn gặp sự cố thì hãy kiểm tra nhật ký apache, nó có thể sẽ cung cấp cho bạn các gợi ý hữu ích:

/private/var/log/apache2/error_log

Nếu bạn sử dụng MAMP làm máy chủ apache localhost, hãy đảm bảo RewriteBase đầu tiên là một liên kết tương đối. ví dụ: RewriteBase / angularjs_site_folder /
David Douglas

3

Sử dụng chế độ HTML5 yêu cầu viết lại URL ở phía máy chủ, về cơ bản, bạn phải viết lại tất cả các liên kết của bạn đến điểm vào của ứng dụng của bạn (ví dụ: index.html). Yêu cầu <base>thẻ cũng rất quan trọng trong trường hợp này, vì nó cho phép AngularJS phân biệt giữa phần url là cơ sở ứng dụng và đường dẫn nên được ứng dụng xử lý. Để biết thêm thông tin, hãy xem Hướng dẫn dành cho nhà phát triển AngularJS - Sử dụng $ location Chế độ HTML5 phía máy chủ .


Cập nhật

Cách làm: Định cấu hình máy chủ của bạn để hoạt động với html5Mode 1

Khi bạn đã bật html5Mode, #ký tự sẽ không còn được sử dụng trong các url của bạn. Các #biểu tượng là hữu ích vì nó không đòi hỏi cấu hình máy chủ phụ. Không #, url trông đẹp hơn nhiều, nhưng nó cũng yêu cầu viết lại phía máy chủ. Dưới đây là một số ví dụ:

Viết lại Apache

<VirtualHost *:80>
    ServerName my-app

    DocumentRoot /path/to/app

    <Directory /path/to/app>
        RewriteEngine on

        # Don't rewrite files or directories
        RewriteCond %{REQUEST_FILENAME} -f [OR]
        RewriteCond %{REQUEST_FILENAME} -d
        RewriteRule ^ - [L]

        # Rewrite everything else to index.html to allow html5 state links
        RewriteRule ^ index.html [L]
    </Directory>
</VirtualHost>

Nginx viết lại

server {
    server_name my-app;

    index index.html;

    root /path/to/app;

    location / {
        try_files $uri $uri/ /index.html;
    }
}

Azure IIS Viết lại

<system.webServer>
  <rewrite>
    <rules> 
      <rule name="Main Rule" stopProcessing="true">
        <match url=".*" />
        <conditions logicalGrouping="MatchAll">
          <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
          <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
        </conditions>
        <action type="Rewrite" url="/" />
      </rule>
    </rules>
  </rewrite>
</system.webServer>

Viết lại

var express = require('express');
var app = express();

app.use('/js', express.static(__dirname + '/js'));
app.use('/dist', express.static(__dirname + '/../dist'));
app.use('/css', express.static(__dirname + '/css'));
app.use('/partials', express.static(__dirname + '/partials'));

app.all('/*', function(req, res, next) {
    // Just send the index.html for other files to support HTML5Mode
    res.sendFile('index.html', { root: __dirname });
});

app.listen(3006); //the port you want to use

Xem thêm


1

Trong Angular 6, với bộ định tuyến của bạn, bạn có thể sử dụng:

RouterModule.forRoot(routes, { useHash: false })

0

Bạn cũng có thể sử dụng mã dưới đây để chuyển hướng đến trang chính (trang chủ):

{ path: '', redirectTo: 'home', pathMatch: 'full'}

Sau khi chỉ định chuyển hướng của bạn như trên, bạn có thể chuyển hướng các trang khác, ví dụ:

{ path: 'add-new-registration', component: AddNewRegistrationComponent},
{ path: 'view-registration', component: ViewRegistrationComponent},
{ path: 'home', component: HomeComponent}

0

**

Bạn nên sử dụng kiểu HTML 5 (PathLocationStrargety) làm chiến lược vị trí trong Angular

** Bởi vì

  1. Nó tạo ra các URL sạch và thân thiện với SEO giúp người dùng dễ hiểu và dễ nhớ hơn.
  2. Bạn có thể tận dụng kết xuất phía máy chủ, điều này sẽ giúp ứng dụng của chúng tôi tải nhanh hơn, bằng cách hiển thị các trang trong máy chủ trước khi gửi cho khách hàng.

Chỉ sử dụng Hashlocationstrtegy nếu bạn phải hỗ trợ các trình duyệt cũ hơn.

Bấm vào đây để biết thêm

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.