Angular 2/4/5 - Tetapkan href dasar secara dinamis

131

Kami memiliki aplikasi perusahaan yang menggunakan Angular 2 untuk klien. Setiap pelanggan kami memiliki url uniknya sendiri, mis .: https://our.app.com/customer-onedan https://our.app.com/customer-two. Saat ini kami dapat mengatur <base href...>secara dinamis menggunakan document.location. Jadi pengguna hits https://our.app.com/customer-twodan <base href...>bersiap untuk /customer-two... sempurna!

Masalahnya adalah jika pengguna misalnya di https://our.app.com/customer-two/another-pagedan mereka menyegarkan halaman atau mencoba untuk menekan url itu secara langsung, <base href...>set ke /customer-two/another-pagedan sumber daya tidak dapat ditemukan.

Kami telah mencoba yang berikut ini tetapi tidak berhasil:

<!doctype html>
<html>

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

...

Sayangnya kami kehabisan ide. Bantuan apa pun akan luar biasa.

mesin tajam
sumber
1
Sudahkah Anda mencoba sesuatu dengan APP_BASE_HREF ? Saya tidak begitu yakin bagaimana ini akan diterapkan, tetapi tampaknya menjadi sesuatu yang akan berguna ...
Jarod Moser
Tentu saja itu pasti tergantung pada versi router yang Anda gunakan saat ini juga. Apakah Anda menggunakan router versi 3.0.0-alpha.x?
Jarod Moser
Saya menggunakan "@ angular / router": "3.0.0-alpha.7"
sharpmachine
5
Angular 7 - November 2018. ini masih menjadi masalah. jawaban saat ini memberikan solusi parsial. melakukan hal-hal di dalam modul sudut sudah terlambat. karena HTML indeks Anda disajikan, Anda perlu mengetahui dari mana harus menarik skrip. hanya ada 2 cara saya melihatnya - menggunakan asp \ php \ apa saja untuk melayani index.html dengan konten basehref dinamis. atau menggunakan javascript asli langsung di file index.html untuk mengubah konten DOM sebelum menjadi bersudut. keduanya adalah solusi yang buruk untuk masalah umum. sedih.
Stavm
1
Bisakah seseorang menjawab pertanyaan saya juga. stackoverflow.com/questions/53757931/…
Karan

Jawaban:

166

Jawaban yang ditandai di sini tidak menyelesaikan masalah saya, kemungkinan versi sudut yang berbeda. Saya dapat mencapai hasil yang diinginkan dengan angular cliperintah berikut di terminal / shell:

ng build --base-href /myUrl/

ng build --bh /myUrl/ atau ng build --prod --bh /myUrl/

Ini mengubah <base href="https://stackoverflow.com/">ke <base href="https://stackoverflow.com/myUrl/">dalam versi yang dibangun hanya yang sempurna untuk perubahan kami di lingkungan antara pengembangan dan produksi. Bagian terbaiknya adalah tidak ada basis kode yang perlu diubah menggunakan metode ini.


Untuk meringkas, biarkan index.htmlhref dasar Anda sebagai: <base href="https://stackoverflow.com/">lalu jalankan ng build --bh ./dengan cli sudut untuk menjadikannya jalur relatif, atau ganti ./dengan apa pun yang Anda butuhkan.


Memperbarui:

Seperti contoh di atas yang menunjukkan cara melakukannya dari baris perintah, berikut adalah cara menambahkannya ke file konfigurasi angular.json Anda.

Ini akan digunakan untuk semua ng servinguntuk pembangunan lokal

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

Ini adalah konfigurasi khusus untuk build konfigurasi seperti prod:

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

The resmi angular-cli dokumentasi mengacu pada penggunaan.

Zze
sumber
35
Solusi ini membutuhkan build per pelanggan, yang mungkin tidak menyelesaikan masalah OP.
Maxime Morin
1
@MaximeMorin dalam pengalaman saya sejauh ini melakukan ini, ./berfungsi untuk semua lokasi. Jadi sebenarnya menurut saya Anda tidak harus membangun per klien.
Zze
9
@Zze Pengalaman saya dengan ./sangat berbeda. Ini berfungsi sampai pengguna menavigasi ke sebuah rute dan menekan tombol atau tombol segarkan browser. Pada saat itu, penulisan ulang kami menangani panggilan tersebut, menyajikan halaman indeks, tetapi browser menganggap itu ./adalah rute saat ini, bukan folder root aplikasi web. Kami memecahkan masalah OP dengan indeks dinamis (.aspx, .php, .jsp, dll) yang menetapkan href dasar.
Maxime Morin
2
Menggunakan --prodselama pembuatan tidak akan mengubah base hrefnilai Anda, Anda tidak boleh membicarakannya di sini. --prodmemberitahu angular-cliuntuk menggunakan environment.prod.tsfile daripada file default environment.tsdi environmentsfolder Anda
Mattew Eon
1
@MattewEon Itu hanya menunjukkan bahwa itu kompatibel dengan --prodbendera karena mereka berbicara tentang penyebaran di OP.
Zze
57

Inilah yang akhirnya kami lakukan.

Tambahkan ini ke index.html. Ini harus menjadi hal pertama di <head>bagian ini

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

Kemudian di app.module.tsfile tersebut, tambahkan { provide: APP_BASE_HREF, useValue: window['_app_base'] || '/' }ke daftar penyedia, seperti:

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 { }
mesin tajam
sumber
Kesalahan TS7017: Elemen secara implisit memiliki tipe 'apapun' karena tipe 'Jendela' tidak memiliki tanda tangan indeks. useValue: (window as any) ['_app_base'] || '/'membantu
Erkan Buelbuel
Tidak benar-benar berfungsi untuk ng2 terbaru, apakah ada solusinya? (memuat jalur skrip yang buruk, lalu jalur skrip yang baik, tetapi tidak di perangkat seluler)
Amit
1
Menambahkannya sebagai jawaban di bawah ini, karena panjang konten terlalu panjang untuk sebuah komentar.
Krishnan
1
@Amit Silakan lihat jawaban saya di bawah ini untuk pemecahan yang mudah di ng2 terbaru.
Zze
3
Bagaimana Anda mengatasi masalah dengan file lain. Browser saya mencoba memuat localhost: 8080 / main.bundle.js , tetapi tidak bisa karena contextPath saya berbeda? (Ini harus mengambil localhost: 8080 / hello / main.bundle.js. )
Sasa
33

Berdasarkan jawaban (@sharpmachine) Anda, saya dapat sedikit melakukan refaktorisasi lebih lanjut, sehingga kami tidak perlu meretas fungsi di 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 { }

Dan, ./shared/common-functions.util.tsberisi:

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;
}
Krishnan
sumber
1
Saya telah menerapkan aplikasi saya ke subfolder. Url saya sekarang terlihat seperti ini: http://localhost:8080/subfolder/myapp/#/subfolder/myrouteApakah ini tampilan Anda? Apakah Anda tahu cara membuang subfolder setelah # agar bisa begitu saja http://localhost:8080/subfolder/myapp/#/myroute?
techguy2000
Oh. Saya pikir basis href hanya diperlukan untuk LocationStrategy. Dalam kasus saya, saya menggunakan HashLocationStrategy. Jadi saya bahkan tidak perlu mengaturnya. Apakah Anda telah menulis kode khusus untuk menangani penyegaran dengan LocationStrategy?
techguy2000
1
Ya, base hrefhanya diperlukan untuk LocationStrategyAFAIK. Adapun menulis kode khusus untuk menangani penyegaran dengan LocationStrategy, tidak yakin apa yang Anda maksud sebenarnya. Apakah Anda bertanya, bagaimana jika "basis href" saya berubah selama aktivitas di aplikasi saya? Lalu, ya, saya harus melakukan hal yang kotor seperti di window.location.href = '/' + newBaseHref;mana ia harus diubah. Saya tidak terlalu bangga akan hal itu. Juga, untuk memberikan pembaruan, saya menjauh dari solusi peretasan ini di aplikasi saya karena itu menjadi masalah desain bagi saya. Parameter router berfungsi dengan baik, jadi saya tetap menggunakannya.
Krishnan
1
Seperti apa appRoutingProviderpenampilan Anda , Krishnan? Saya melihat jawaban yang diterima digunakan sama; mungkin Anda hanya menyalinnya providers, tetapi jika tidak, dapatkah Anda memberi saya sampel atau menjelaskan tujuannya? The dokumentasi saja importsRouting modul , tidak menggunakan terkait routing penyedia (sejauh yang saya bisa melihat)
The Red Pea
@Krishnan Inilah yang harus saya lakukan dengan nginx agar berhasil:location /subfolder/myapp/ { try_files $uri /subfolder/myapp/index.html; } location /subfolder2/myapp/ { try_files $uri /subfolder2/myapp/index.html; }
techguy2000
24

Saya menggunakan direktori kerja saat ini ./ketika membangun beberapa aplikasi dari domain yang sama:

<base href="./">

Di samping catatan, saya gunakan .htaccessuntuk membantu perutean saya saat memuat ulang halaman:

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* index.html [L]
Daerik
sumber
2
Terima kasih banyak atas .htaccessfilenya
Shahriar Siraj Snigdho
8
Jawaban ini salah, tidak berfungsi untuk rute seperti / aplikasi-Anda / a / b / c. Jika Anda menyegarkan halaman Anda dari rute seperti itu, Angular akan mencari runtime, polyfills dan file JS utama dan file CSS gaya di bawah / aplikasi-Anda / a / b /. Mereka jelas tidak berada di lokasi itu, tetapi di / aplikasi-Anda /
toongeorges
2
@toongeorges Jawaban ini ditulis hampir dua tahun yang lalu menggunakan file konfigurasi yang dideteksi dan dijalankan oleh perangkat lunak Apache Web Server untuk menangani perutean pada pemuatan ulang halaman. Bagi Anda untuk mengatakan solusi ini tidak benar dan tidak berfungsi itu menyesatkan, tetapi yang Anda maksud adalah Anda tidak dapat menemukan cara untuk membuatnya bekerja dengan konfigurasi Anda.
Daerik
Saya mengabaikan aturan penulisan ulang Apache dan saya tidak cukup tahu tentang hal itu untuk mengatakan bahwa ini tidak akan berfungsi di Apache, jadi saya mungkin salah dan jawaban Anda mungkin benar. Meskipun bagaimanapun saya lebih suka solusi yang tidak mengharuskan Anda untuk mengubah konfigurasi server karena telah diberikan beberapa jawaban di sini, karena ini membuat aplikasi portabel di berbagai server.
toongeorges
2
Nah, @toongeorges benar, mengganti menjadi <base href="./">salah dan akan mengacaukan rute seperti /app/a/b/cmemang, coba saja. Lebih suka mengatur href dasar sendiri jika hanya berurusan dengan aplikasi web atau lihat cara sudut mengubah href dasar saat menerapkan (ada banyak jawaban di sini yang menyebutkan ini).
giovannipds
15

Penyederhanaan jawaban yang ada oleh @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 { }

Anda tidak perlu menentukan tag dasar di index.html Anda, jika Anda memberikan nilai untuk token buram APP_BASE_HREF.

Karanvir Kang
sumber
10

Ini bekerja dengan baik untuk saya di lingkungan produksi

<base href="https://stackoverflow.com/" id="baseHref">
<script>
  (function() {
    document.getElementById('baseHref').href = '/' + window.location.pathname.split('/')[1] + "/";
  })();
</script>
Avikar
sumber
2
Solusi ini memiliki batasan besar dengan beberapa pengaturan VD di IIS. Ini menyebabkan pemuatan duplikat potongan.
Karan
9

Di angular4, Anda juga dapat mengonfigurasi baseHref di aplikasi .angular-cli.json.

di .angular-cli.json

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

ini akan memperbarui basis href di index.html menjadi MY_APP_BASE_HREF_1

ng build --app myapp1
Vince
sumber
4
Ini juga perlu membuat build untuk setiap aplikasi.
Patrick Hillert
6

Jika Anda menggunakan Angular CLI 6, Anda dapat menggunakan opsi deployUrl / baseHref di angular.json (proyek> xxx> arsitek> build> konfigurasi> produksi). Dengan cara ini, Anda dapat dengan mudah menentukan baseUrl per proyek.

Periksa apakah pengaturan Anda sudah benar dengan melihat index.html dari aplikasi yang dibangun.

Katlu
sumber
7
ini membutuhkan build yang berbeda untuk setiap lingkungan, dengan semua implikasinya.
Stavm
3

Add-ons: Jika Anda menginginkan mis: / users sebagai basis aplikasi untuk router dan / public sebagai basis untuk penggunaan aset

$ ng build -prod --base-href /users --deploy-url /public
3rdi
sumber
1

Punya masalah serupa, sebenarnya saya akhirnya menyelidiki keberadaan beberapa file di web saya.

probePath akan menjadi URL relatif ke file yang ingin Anda periksa (semacam penanda jika Anda sekarang berada di lokasi yang benar), misalnya 'assets / 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>
Ronald Korze
sumber
0

Dalam package.json setel flag --base-href ke jalur relatif:

"script": {
    "build": "ng build --base-href ./"
}
Jarek Wichrowski
sumber
-1

Terus terang, kasus Anda berfungsi dengan baik untuk saya!

Saya menggunakan 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>
Aviw
sumber
Apakah solusi ini berhasil untuk Anda? Saya menghadapi masalah. Bisakah Anda membalas posting saya juga. stackoverflow.com/questions/53757931/…
Karan
1
Harap hindari menggunakan document.write (): developers.google.com/web/updates/2016/08/…
Patrick Hillert
-6

Saya baru saja mengubah:

  <base href="/">

untuk ini:

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

jangan lupa diakhiri dengan /

Huy - Logarit
sumber