Angular 2/4/5 - Đặt động cơ sở href


131

Chúng tôi có một ứng dụng doanh nghiệp sử dụng Angular 2 cho khách hàng. Mỗi khách hàng của chúng tôi có url duy nhất của riêng họ, ví dụ: https://our.app.com/customer-onehttps://our.app.com/customer-two. Hiện tại, chúng tôi có thể thiết lập <base href...>động bằng cách sử dụng document.location. Vì vậy, người dùng truy cập https://our.app.com/customer-two<base href...>được đặt thành /customer-two... hoàn hảo!

Vấn đề là nếu người dùng chẳng hạn tại https://our.app.com/customer-two/another-pagevà họ làm mới trang hoặc cố gắng truy cập trực tiếp vào url đó, <base href...>nó sẽ được đặt thành /customer-two/another-pagevà không thể tìm thấy tài nguyên.

Chúng tôi đã thử những cách sau nhưng không có kết quả:

<!doctype html>
<html>

<head>
  <script type='text/javascript'>
    var base = document.location.pathname.split('/')[1];
    document.write('<base href="https://stackoverflow.com/' + base + '" />');
  </script>

...

Thật không may, chúng tôi không có ý tưởng mới. Bất kỳ trợ giúp sẽ là tuyệt vời.


1
Bạn đã thử bất cứ điều gì với APP_BASE_HREF chưa? Tôi không hoàn toàn chắc chắn làm thế nào nó sẽ được thực hiện, nhưng nó có vẻ là một cái gì đó sẽ có ích ...
Jarod Moser

Tất nhiên, nó chắc chắn phụ thuộc vào phiên bản bộ định tuyến mà bạn hiện đang sử dụng. Bạn có đang sử dụng phiên bản bộ định tuyến 3.0.0-alpha.x không?
Jarod Moser

Tôi đang sử dụng "@ angle / router": "3.0.0-alpha.7"
sharpmachine

5
Angular 7 - Tháng 11 năm 2018. Đây vẫn là một vấn đề. câu trả lời hiện tại cung cấp một giải pháp từng phần. làm những thứ bên trong mô-đun góc là quá muộn. khi HTML chỉ mục của bạn được phân phát, nó cần biết nơi lấy các tập lệnh từ đó. chỉ có 2 cách theo cách mà tôi thấy - sử dụng asp \ php \ bất cứ thứ gì để cung cấp index.html với nội dung basehref động. hoặc sử dụng javascript gốc ngay trên tệp index.html để thay đổi nội dung DOM trước khi chuyển sang dạng góc. cả hai đều là giải pháp kém cho một vấn đề chung. buồn.
Stavm

1
Ai đó cũng có thể vui lòng trả lời câu hỏi của tôi. stackoverflow.com/questions/53757931/…
Karan

Câu trả lời:


166

Câu trả lời được đánh dấu ở đây không giải quyết được vấn đề của tôi, có thể là các phiên bản góc cạnh khác nhau. Tôi đã có thể đạt được kết quả mong muốn với angular clilệnh sau trong terminal / shell:

ng build --base-href /myUrl/

ng build --bh /myUrl/ hoặc là ng build --prod --bh /myUrl/

Điều này thay đổi thành <base href="https://stackoverflow.com/">chỉ <base href="https://stackoverflow.com/myUrl/">trong phiên bản đã xây dựng , vốn hoàn hảo cho sự thay đổi của chúng tôi trong môi trường giữa phát triển và sản xuất. Phần tốt nhất là không có cơ sở mã yêu cầu thay đổi bằng cách sử dụng phương pháp này.


Tóm lại, để lại index.htmlhref cơ sở của bạn là: <base href="https://stackoverflow.com/">sau đó chạy ng build --bh ./với cli góc để biến nó thành một đường dẫn tương đối hoặc thay thế ./bằng bất cứ thứ gì bạn yêu cầu.


Cập nhật:

Như ví dụ trên cho thấy cách thực hiện điều đó từ dòng lệnh, đây là cách thêm nó vào tệp cấu hình angle.json của bạn.

Điều này sẽ được sử dụng cho tất cả ng servingđể phát triển địa phương

"architect": {
    "build": {
      "builder": "@angular-devkit/build-angular:browser",
      "options": {
        "baseHref": "/testurl/",

Đây là cấu hình cụ thể cho các bản dựng cấu hình như sản phẩm:

"configurations": {
   "Prod": {
     "fileReplacements": [
        {
          "replace": src/environments/environment.ts",
          "with": src/environments/environment.prod.ts"
        }
      ],
      "baseHref": "./productionurl/",

Các quan chức angular-cli tài liệu đề cập đến cách sử dụng.


35
Giải pháp này yêu cầu một bản dựng cho mỗi khách hàng, điều này có lẽ không giải quyết được vấn đề của OP.
Maxime Morin

1
@MaximeMorin theo kinh nghiệm của tôi cho đến nay khi làm việc này, ./hoạt động cho tất cả các vị trí. Vì vậy, tôi không nghĩ rằng bạn phải xây dựng cho mỗi khách hàng.
Zze

9
@Zze Trải nghiệm của tôi với ./rất khác. Nó hoạt động cho đến khi người dùng điều hướng đến một tuyến đường và nhấn vào nút hoặc các phím làm mới của trình duyệt. Tại thời điểm đó, các đoạn viết lại của chúng tôi xử lý cuộc gọi, phục vụ trang chỉ mục, nhưng trình duyệt giả định rằng đó ./là tuyến hiện tại không phải thư mục gốc của ứng dụng web. Chúng tôi đã giải quyết vấn đề của OP bằng chỉ mục động (.aspx, .php, .jsp, v.v.) đặt href cơ sở.
Maxime Morin

2
Việc sử dụng --prodtrong quá trình xây dựng sẽ không thay đổi base hrefgiá trị của bạn , bạn không nên nói về nó ở đây. --prodyêu angular-clicầu sử dụng environment.prod.tstệp thay vì tệp mặc định environment.tstrong environmentsthư mục của bạn
Mattew Eon

1
@MattewEon Nó chỉ chứng minh rằng nó tương thích với --prodcờ vì họ đang nói về việc triển khai trong OP.
Zze

57

Đây là những gì chúng tôi đã kết thúc.

Thêm cái này vào index.html. Nó phải là điều đầu tiên trong <head>phần

<base href="https://stackoverflow.com/">
<script>
  (function() {
    window['_app_base'] = '/' + window.location.pathname.split('/')[1];
  })();
</script>

Sau đó, trong app.module.tstệp, thêm { provide: APP_BASE_HREF, useValue: window['_app_base'] || '/' }vào danh sách các nhà cung cấp, như sau:

import { NgModule, enableProdMode, provide } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { APP_BASE_HREF, Location } from '@angular/common';


import { AppComponent, routing, appRoutingProviders, environment } from './';

if (environment.production) {
  enableProdMode();
}

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    HttpModule,
    routing],
  bootstrap: [AppComponent],
  providers: [
    appRoutingProviders,
    { provide: APP_BASE_HREF, useValue: window['_app_base'] || '/' },
  ]
})
export class AppModule { }

Lỗi TS7017: Phần tử ngầm định có kiểu 'bất kỳ' vì kiểu 'Cửa sổ' không có chữ ký chỉ mục. useValue: (window as any) ['_app_base'] || '/'giúp đỡ
Erkan Buelbuel 19/12/16

Không thực sự hoạt động cho ng2 mới nhất, có một giải pháp? (đường dẫn script tải xấu, sau đó tốt kịch bản con đường, nhưng không phải trên điện thoại di động)
Amit

1
Thêm nó làm câu trả lời bên dưới, vì độ dài nội dung quá dài cho một nhận xét.
Krishnan

1
@Amit Vui lòng xem câu trả lời của tôi bên dưới để có cách giải dễ dàng trong ng2 mới nhất.
Zze

3
Bạn đã giải quyết vấn đề với các tệp khác như thế nào. Trình duyệt của tôi đang cố tải localhost: 8080 / main.bundle.js , nhưng không thể vì contextPath của tôi khác? (Nó phải được tìm nạp localhost: 8080 / hello / main.bundle.js. )
Sasa

33

Dựa trên câu trả lời (@sharpmachine) của bạn, tôi đã có thể cấu trúc lại nó một chút, để chúng ta không phải hack một chức năng trong đó index.html.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { APP_BASE_HREF, Location } from '@angular/common';

import { AppComponent } from './';
import { getBaseLocation } from './shared/common-functions.util';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    HttpModule,
  ],
  bootstrap: [AppComponent],
  providers: [
    appRoutingProviders,
    {
        provide: APP_BASE_HREF,
        useFactory: getBaseLocation
    },
  ]
})
export class AppModule { }

Và, ./shared/common-functions.util.tschứa:

export function getBaseLocation() {
    let paths: string[] = location.pathname.split('/').splice(1, 1);
    let basePath: string = (paths && paths[0]) || 'my-account'; // Default: my-account
    return '/' + basePath;
}

1
Tôi đã triển khai myapp tới thư mục con. Url của tôi bây giờ trông như thế này: http://localhost:8080/subfolder/myapp/#/subfolder/myrouteĐây có phải là url của bạn trông như thế này không? Bạn có biết cách loại bỏ thư mục con sau dấu # để nó có thể http://localhost:8080/subfolder/myapp/#/myroutenhư vậy không?
techguy2000

Oh. Tôi nghĩ rằng cơ sở href chỉ cần thiết cho LocationStrategy. Trong trường hợp của tôi, tôi đang sử dụng HashLocationStrategy. Vì vậy, tôi thậm chí không cần thiết lập nó. Bạn đã viết mã đặc biệt để xử lý làm mới với LocationStrategy chưa?
techguy2000

1
Có, base hrefchỉ bắt buộc đối với LocationStrategyAFAIK. Đối với việc viết mã đặc biệt để xử lý làm mới với LocationStrategy, không chắc bạn muốn nói gì chính xác. Bạn đang hỏi, điều gì sẽ xảy ra nếu "base href" của tôi thay đổi trong một hoạt động trong ứng dụng của tôi? Sau đó, vâng, tôi đã phải làm một điều bẩn thỉu như window.location.href = '/' + newBaseHref;nơi bắt buộc phải thay đổi. Tôi không quá tự hào về nó. Ngoài ra, để cập nhật, tôi đã tránh xa các giải pháp hack này trong ứng dụng của mình vì nó đang trở thành vấn đề thiết kế đối với tôi. Các thông số của bộ định tuyến hoạt động hoàn toàn tốt, vì vậy tôi mắc kẹt với nó.
Krishnan

1
appRoutingProviderTrông bạn như thế nào, Krishnan? Tôi thấy câu trả lời được chấp nhận được sử dụng giống nhau; có thể bạn chỉ cần sao chép của mình providers, nhưng nếu không, bạn có thể cho tôi một mẫu hoặc mô tả mục đích của nó? Các tài liệu chỉ importsmodule định tuyến , nó không sử dụng bất kỳ nhà cung cấp định tuyến có liên quan (như xa như tôi có thể nhìn thấy)
The Red Pea

@Krishnan Dưới đây là những gì tôi phải làm với nginx để làm cho nó làm việc:location /subfolder/myapp/ { try_files $uri /subfolder/myapp/index.html; } location /subfolder2/myapp/ { try_files $uri /subfolder2/myapp/index.html; }
techguy2000

24

Tôi sử dụng thư mục làm việc hiện tại ./khi tạo một số ứng dụng trên cùng một miền:

<base href="./">

Lưu ý nhỏ, tôi sử dụng .htaccessđể hỗ trợ định tuyến khi tải lại trang:

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* index.html [L]

2
Cảm ơn bạn rất nhiều vì .htaccesstệp tin
Shahriar Siraj Snigdho

8
Câu trả lời này không chính xác, nó không hoạt động đối với các tuyến như / your-app / a / b / c. Nếu bạn làm mới trang của mình từ một lộ trình như vậy, Angular sẽ tìm kiếm thời gian chạy, polyfills và các tệp JS chính và tệp CSS định kiểu trong / your-app / a / b /. Rõ ràng là họ không ở vị trí đó, mà ở dưới / your-app /
toongeorges,

2
@toongeorges Câu trả lời này được viết gần hai năm trước bằng cách sử dụng tệp cấu hình được phát hiện và thực thi bởi phần mềm Máy chủ Web Apache để xử lý định tuyến khi tải lại trang. Đối với bạn mà nói giải pháp này không chính xác và không hoạt động là gây hiểu lầm, nhưng ý bạn là bạn không thể tìm ra cách làm cho nó hoạt động với cấu hình của bạn.
Daerik

Tôi đã bỏ qua quy tắc ghi lại Apache và tôi không biết đủ về nó để nói rằng điều này sẽ không hoạt động trên Apache, vì vậy tôi có thể sai và câu trả lời của bạn có thể đúng. Mặc dù trong mọi trường hợp, tôi thích giải pháp không yêu cầu bạn sửa đổi cấu hình máy chủ vì đã có nhiều câu trả lời ở đây, vì điều này làm cho ứng dụng có thể di động trên các máy chủ khác nhau.
toongeorges

2
Không, @toongeorges đúng, thay đổi thành <base href="./">là sai và sẽ làm hỏng các tuyến đường như /app/a/b/cthực sự, chỉ cần thử nghiệm nó. Thích tự đặt href cơ sở nếu chỉ xử lý một ứng dụng web hoặc xem xét cách thay đổi cơ sở href khi triển khai (có rất nhiều câu trả lời ở đây đề cập đến điều này).
giovannipds

15

Đơn giản hóa câu trả lời hiện có bằng @sharpmachine .

import { APP_BASE_HREF } from '@angular/common';
import { NgModule } from '@angular/core';

@NgModule({
    providers: [
        {
            provide: APP_BASE_HREF,
            useValue: '/' + (window.location.pathname.split('/')[1] || '')
        }
    ]
})

export class AppModule { }

Bạn không phải chỉ định thẻ cơ sở trong index.html của mình, nếu bạn đang cung cấp giá trị cho mã thông báo không trong suốt APP_BASE_HREF.


10

Điều này làm việc tốt cho tôi trong môi trường sản xuất

<base href="https://stackoverflow.com/" id="baseHref">
<script>
  (function() {
    document.getElementById('baseHref').href = '/' + window.location.pathname.split('/')[1] + "/";
  })();
</script>

2
Giải pháp này có một hạn chế lớn với nhiều thiết lập VD trong IIS. Nó gây ra tải trùng lặp các khối.
Karan

9

Trong angle4, bạn cũng có thể định cấu hình baseHref trong các ứng dụng .angular-cli.json.

trong .angular-cli.json

{   ....
 "apps": [
        {
            "name": "myapp1"
            "baseHref" : "MY_APP_BASE_HREF_1"
         },
        {
            "name": "myapp2"
            "baseHref" : "MY_APP_BASE_HREF_2"
         },
    ],
}

điều này sẽ cập nhật href cơ sở trong index.html thành MY_APP_BASE_HREF_1

ng build --app myapp1

4
Điều này cũng cần tạo bản dựng cho từng ứng dụng.
Patrick Hillert

6

Nếu bạn đang sử dụng Angular CLI 6, bạn có thể sử dụng tùy chọn deployUrl / baseHref trong angle.json (các dự án> xxx> kiến ​​trúc> xây dựng> cấu hình> sản xuất). Bằng cách này, bạn có thể dễ dàng chỉ định baseUrl cho mỗi dự án.

Kiểm tra xem cài đặt của bạn có chính xác không bằng cách xem index.html của ứng dụng đã xây dựng.


7
điều này đòi hỏi một bản dựng khác nhau cho từng môi trường, với tất cả các hàm ý của nó.
Stavm

3

Tiện ích bổ sung: Nếu bạn muốn, ví dụ: / người dùng làm cơ sở ứng dụng cho bộ định tuyến và / công khai làm cơ sở cho việc sử dụng nội dung

$ ng build -prod --base-href /users --deploy-url /public

1

Gặp sự cố tương tự, thực sự là tôi đã kết thúc việc thăm dò sự tồn tại của một số tệp trong web của tôi.

probePath sẽ là URL liên quan đến tệp bạn muốn kiểm tra (loại điểm đánh dấu nếu bạn đang ở đúng vị trí), ví dụ: 'asset / images / thisImageAlwaysExists.png'

<script type='text/javascript'>
  function configExists(url) {
    var req = new XMLHttpRequest();
    req.open('GET', url, false); 
    req.send();
    return req.status==200;
  }

  var probePath = '...(some file that must exist)...';
  var origin = document.location.origin;
  var pathSegments = document.location.pathname.split('/');

  var basePath = '/'
  var configFound = false;
  for (var i = 0; i < pathSegments.length; i++) {
    var segment = pathSegments[i];
    if (segment.length > 0) {
      basePath = basePath + segment + '/';
    }
    var fullPath = origin + basePath + probePath;
    configFound = configExists(fullPath);
    if (configFound) {
      break;
    }
  }

  document.write("<base href='" + (configFound ? basePath : '/') + "' />");
</script>

0

Trong package.json, đặt cờ --base-href thành đường dẫn tương đối:

"script": {
    "build": "ng build --base-href ./"
}

-1

Thành thật mà nói, trường hợp của bạn phù hợp với tôi!

Tôi đang sử dụng Angular 5.

<script type='text/javascript'>
    var base = window.location.href.substring(0, window.location.href.toLowerCase().indexOf('index.aspx'))
    document.write('<base href="' + base + '" />');
</script>

Giải pháp này có hiệu quả với bạn không? Tôi đang đối mặt với vấn đề. Bạn có thể vui lòng trả lời bài viết của tôi. stackoverflow.com/questions/53757931/…
Karan

1
Hãy tránh sử dụng document.write (): developers.google.com/web/updates/2016/08/...
Patrick Hillert

-6

Tôi vừa thay đổi:

  <base href="/">

đến điều này:

  <base href="/something.html/">

đừng quên kết thúc bằng /

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.