Açısal 2/4/5 - Temel href'i dinamik olarak ayarla


131

Müşteri için Angular 2 kullanan kurumsal bir uygulamamız var. Müşterilerimizin her birinin kendi benzersiz url'si vardır, örn: https://our.app.com/customer-oneve https://our.app.com/customer-two. Şu anda <base href...>kullanarak dinamik olarak ayarlayabiliyoruz document.location. Böylece kullanıcı vurur https://our.app.com/customer-twove <base href...>ayarlanır /customer-two... mükemmel!

Sorun, kullanıcı örneğin adresindeyse https://our.app.com/customer-two/another-pageve sayfayı yenilerse veya bu url'ye doğrudan ulaşmaya çalışırsa, <base href...>ayarlanır /customer-two/another-pageve kaynaklar bulunamaz.

Aşağıdakileri boşuna denedik:

<!doctype html>
<html>

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

...

Maalesef fikirlerimiz tükendi. Herhangi bir yardım Muhteşem olacak.


1
APP_BASE_HREF ile herhangi bir şey denediniz mi? Nasıl uygulanacağından tam olarak emin değilim, ancak faydalı olacak bir şey gibi görünüyor ...
Jarod Moser

Elbette, şu anda kullandığınız yönlendiricinin hangi sürümüne de bağlı. Yönlendirici 3.0.0-alpha.x sürümünü mü kullanıyorsunuz?
Jarod Moser

"@ Angular / router": "3.0.0-alpha.7" kullanıyorum
sharpmachine

5
Angular 7 - Kasım 2018. bu hala bir sorundur. mevcut cevaplar kısmi bir çözüm sağlar. açısal modülün içinde bir şeyler yapmak çok geç. HTML indeksiniz sunulduğunda, komut dosyalarını nereden çekeceğini bilmesi gerekir. benim gördüğüm yolun sadece 2 yolu var - dinamik basehref içeriğiyle index.html'ye hizmet etmek için asp \ php \ ne kullanıyorsun. veya DOM içeriğini açısal hale gelmeden önce değiştirmek için index.html dosyasında yerel javascript kullanarak. her ikisi de ortak bir soruna kötü çözümler. üzgün.
Stavm

1
Birisi benim sorguma da cevap verebilir mi? stackoverflow.com/questions/53757931/…
Karan

Yanıtlar:


166

Buradaki işaretli cevap sorunumu, muhtemelen farklı açısal versiyonları çözmedi. angular cliTerminal / kabuk'ta aşağıdaki komutla istenen sonucu elde etmeyi başardım :

ng build --base-href /myUrl/

ng build --bh /myUrl/ veya ng build --prod --bh /myUrl/

Bu değişiklikler <base href="https://stackoverflow.com/">için <base href="https://stackoverflow.com/myUrl/">de sadece dahili sürümü geliştirme ve üretim arasındaki ortamda bizim değişim için mükemmeldi. En iyi yanı, bu yöntemi kullanarak kod tabanının değiştirilmesini gerektirmemesiydi.


Özetlemek gerekirse, index.htmltemel href'inizi şu şekilde bırakın : <base href="https://stackoverflow.com/">sonra ng build --bh ./onu göreceli bir yol yapmak için açısal cli ile çalıştırın veya ihtiyacınız olanla değiştirin ./.


Güncelleme:

Yukarıdaki örnekte komut satırından nasıl yapılacağı gösterildiği gibi, işte bunu angular.json yapılandırma dosyanıza nasıl ekleyeceğiniz.

Bu herkes ng servingiçin yerel kalkınma için kullanılacak

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

Bu, prod gibi yapılandırma yapılarına özgü yapılandırmadır:

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

Kullanımla ilgili resmi angular-cli belgeler.


35
Bu çözüm, muhtemelen OP'nin problemini çözmeyen müşteri başına bir yapı gerektirir.
Maxime Morin

1
@MaximeMorin şu ana kadar yaptığım deneyimlere göre, ./tüm lokasyonlar için çalışıyor. Yani aslında müşteri başına inşa etmeniz gerektiğini düşünmüyorum.
Zze

9
@Zze ile yaşadığım deneyim ./çok farklı oldu. Kullanıcı bir rotaya gidene ve tarayıcının yenile düğmesine veya tuşlarına basana kadar çalışır. Bu noktada, yeniden yazmalarımız çağrıyı ele alır, dizin sayfasını sunar, ancak tarayıcı ./web uygulamasının kök klasörü değil, geçerli yolun bu olduğunu varsayar . OP'nin sorununu temel href'i ayarlayan dinamik (.aspx, .php, .jsp, vb.) Bir dizinle çözdük.
Maxime Morin

2
Yapım --prodsırasında kullanmak base hrefdeğerinizi değiştirmez, burada bundan bahsetmemelisiniz. --prodsöyler angular-clikullanmak environment.prod.tsvarsayılan dosya yerine dosyayı environment.tssizin de environmentsklasörünün
Mattew Eon

1
@MattewEon Sadece --prodOP'de konuşlandırmadan bahsederken bayrakla uyumlu olduğunu gösteriyordu .
Zze

57

İşte sonunda yaptığımız şey.

Bunu index.html'ye ekleyin. Bu ilk şey olmalıdır <head>bölümünde

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

Ardından app.module.tsdosyada { provide: APP_BASE_HREF, useValue: window['_app_base'] || '/' }, aşağıdaki gibi sağlayıcılar listesine ekleyin :

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

Hata TS7017: Öğe örtük olarak 'herhangi' bir türe sahip çünkü 'Pencere' türünde dizin imzası yok. useValue: (window as any) ['_app_base'] || '/'yardım eder
Erkan Buelbuel

En son ng2 için gerçekten çalışmıyor, bir çözüm var mı? (kötü komut dosyası yolunu yükler, ardından iyi komut dosyası yolunu yükler, ancak mobil cihazlarda değil)
Amit

1
İçerik uzunluğu bir yorum için çok uzun olduğundan, bunu aşağıda yanıt olarak eklemek.
Krishnan

1
@ Kabul En yeni ng2'de kolay bir çözüm için lütfen aşağıdaki cevabıma bakın.
Zze

3
Diğer dosyalarla ilgili sorunu nasıl çözdünüz? Tarayıcım localhost: 8080 / main.bundle.js'yi yüklemeye çalışıyor , ancak yapamıyor çünkü contextPath farklı mı? ( Localhost'u getirmelidir : 8080 / merhaba / main.bundle.js. )
Sasa

33

(@Sharpmachine) cevabınıza dayanarak, onu biraz daha yeniden düzenleyebildim, böylece bir işlevi kırmak zorunda kalmayız 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 { }

Ve ./shared/common-functions.util.tsşunları içerir:

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
Uygulamamı alt klasöre yerleştirdim. Benim url’im şimdi şöyle görünüyor: http://localhost:8080/subfolder/myapp/#/subfolder/myrouteSizinki böyle mi görünüyor? # İşaretinden sonra alt klasörden nasıl kurtulacağınızı biliyor musunuz http://localhost:8080/subfolder/myapp/#/myroute?
techguy2000

Ah. Sanırım href tabanı yalnızca LocationStrategy için gerekli. Benim durumumda HashLocationStrategy kullanıyorum. Yani ayarlamama bile gerek yok. LocationStrategy ile yenilemeyi işlemek için özel bir kod yazdınız mı?
techguy2000

1
Evet, base hrefyalnızca LocationStrategyAFAIK için gereklidir . LocationStrategy ile yenilemeyi işlemek için özel kod yazmaya gelince, tam olarak ne demek istediğinizden emin değilim. Uygulamamdaki bir etkinlik sırasında "temel href" değerim değişirse ne olur diye mi soruyorsunuz? Sonra, evet, window.location.href = '/' + newBaseHref;değiştirilmesi gereken yer gibi kirli bir şey yapmak zorunda kaldım . Onunla çok gurur duymuyorum. Ayrıca bir güncelleme vermek için uygulamamdaki bu hack çözümlerinden uzaklaştım çünkü benim için bir tasarım sorunu haline geliyordu. Yönlendirici parametreleri mükemmel çalışıyor, ben de buna bağlı kaldım.
Krishnan

1
Nasıl appRoutingProvidergörünüyorsun Krishnan? Kabul edilen cevabın da aynı şekilde kullanıldığını görüyorum; belki onu kopyaladınız providers, ama değilse, bana bir örnek verebilir misiniz veya amacını açıklayabilir misiniz? Sadece dokümantasyon importsmodüllerini yönlendirme , bu (görebildiğim kadarıyla) Herhangi yönlendirme-ilişkili sağlayıcıları kullanmaz
The Red Pea

@Krishnan İşte çalışması için nginx ile yapmam gerekenler:location /subfolder/myapp/ { try_files $uri /subfolder/myapp/index.html; } location /subfolder2/myapp/ { try_files $uri /subfolder2/myapp/index.html; }
techguy2000

24

./Aynı etki alanı dışında birkaç uygulama oluştururken mevcut çalışma dizinini kullanıyorum :

<base href="./">

Bir yan not olarak, .htaccesssayfanın yeniden yüklenmesinde yönlendirmeme yardımcı olmak için kullanıyorum :

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

2
.htaccessDosya için çok teşekkür ederim
Shahriar Siraj Snigdho

8
Bu cevap yanlış, / uygulamanız / a / b / c gibi rotalarda çalışmıyor. Sayfanızı böyle bir rotadan yenilerseniz, Angular çalışma zamanı, çoklu dolgular ve ana JS dosyalarını ve CSS dosyasını / uygulamanız / a / b / altında arayacaktır.
Belli

2
@toongeorges Bu yanıt, yaklaşık iki yıl önce, sayfanın yeniden yüklenmesi sırasında yönlendirmeyi işlemek için Apache Web Sunucusu yazılımı tarafından algılanan ve çalıştırılan bir yapılandırma dosyası kullanılarak yazılmıştır. Sizin için bu çözümün yanlış olduğunu ve işe yaramadığını söylemeniz yanıltıcıdır, ancak demek istediğiniz, yapılandırmanızla nasıl çalıştıracağınızı çözemediğinizdir.
Daerik

Apache yeniden yazma kuralını göz ardı ettim ve bunun Apache üzerinde çalışmayacağını söyleyecek kadar bilgim yok, bu yüzden yanılıyor olabilirim ve cevabınız doğru olabilir. Her durumda, burada birden çok yanıt verildiği için sunucu yapılandırmasını değiştirmenizi gerektirmeyen bir çözümü tercih ediyorum, çünkü bu, uygulamayı farklı sunucular arasında taşınabilir hale getirir.
toongeorges

2
Hayır, @toongeorges haklı, yerine geçmek <base href="./">yanlış ve /app/a/b/cgerçekten gibi rotalarla mahvolacak , az önce test ettim. Yalnızca bir web uygulamasıyla uğraşıyorsanız temel href'i kendiniz ayarlamayı tercih edin veya dağıtımda temel href'i değiştirmenin açısal yoluna bir göz atın (burada bundan bahseden birçok yanıt var).
giovannipds

15

Mevcut yanıtın @sharpmachine tarafından basitleştirilmesi .

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

APP_BASE_HREF opak belirteci için değer sağlıyorsanız, index.html'nizde bir temel etiket belirtmeniz gerekmez.


10

Bu, üretim ortamında benim için iyi çalışıyor

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

2
Bu çözüm, IIS'de çoklu VD kurulumuyla büyük bir sınırlamaya sahiptir. Parçaların mükerrer yüklenmesine neden olur.
Karan

9

Angular4'te, baseHref'i .angular-cli.json uygulamalarında da yapılandırabilirsiniz.

.angular-cli.json içinde

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

bu, index.html'deki temel href'i MY_APP_BASE_HREF_1 olarak günceller

ng build --app myapp1

4
Bunun ayrıca her uygulama için bir derleme yapması gerekir.
Patrick Hillert

6

Angular CLI 6 kullanıyorsanız, angular.json'da deployUrl / baseHref seçeneklerini kullanabilirsiniz (projeler> xxx> mimar> inşa> konfigürasyonlar> üretim). Bu şekilde, proje başına baseUrl değerini kolayca belirtebilirsiniz.

Yerleşik uygulamanın index.html'sine bakarak ayarlarınızın doğru olup olmadığını kontrol edin.


7
bu, tüm sonuçlarıyla birlikte her ortam için farklı bir yapı gerektirir.
Stavm

3

Eklentiler: Örneğin isterseniz: yönlendirici için uygulama tabanı olarak / kullanıcılar ve varlıkların kullanımı için temel olarak / public

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

1

Benzer bir sorun yaşadım, aslında web'imde bir dosyanın varlığını araştırmaya başladım.

probePath , kontrol etmek istediğiniz dosyanın göreli URL'si olacaktır (şu anda doğru konumdaysanız bir tür işaretçi), örneğin, '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>

0

Package.json içinde --base-href bayrağını göreli yola ayarlayın:

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

-1

Açıkçası, davanız benim için iyi çalışıyor!

Angular 5 kullanıyorum.

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

Bu çözüm sizin için çalıştı mı? Sorunla karşı karşıyayım. Lütfen benim yazıma da cevap verir misin? stackoverflow.com/questions/53757931/…
Karan

1
Lütfen document.write () kullanmaktan kaçının: developers.google.com/web/updates/2016/08/…
Patrick Hillert

-6

Az önce değiştim:

  <base href="/">

buna:

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

/ ile bitmeyi unutma

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.