簡體   English   中英

Angular 2+ - 動態設置 base href

[英]Angular 2+ - Set base href dynamically

我們有一個企業應用程序,它為客戶端使用 Angular 2。 我們的每個客戶都有自己獨特的 url,例如: https://our.app.com/customer-onehttps://our.app.com/customer-two 目前我們可以使用document.location動態設置<base href...> 所以用戶點擊https://our.app.com/customer-two並且<base href...>被設置為/customer-two ...完美!

問題是,如果用戶位於https://our.app.com/customer-two/another-page並且他們刷新頁面或嘗試直接點擊 url,則<base href...>被設置到/customer-two/another-page並且找不到資源。

我們嘗試了以下無濟於事:

<!doctype html>
<html>

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

...

不幸的是,我們還沒有想法。 任何幫助都會很棒。

這里的標記答案並沒有解決我的問題,可能是不同的角度版本。 我能夠在終端/外殼中使用以下angular cli命令實現預期的結果:

ng build --base-href /myUrl/

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

僅將構建版本中的<base href="/">更改為<base href="/myUrl/"> ,這非常適合我們在開發和生產之間更改環境。 最好的部分是沒有代碼庫需要使用這種方法進行更改。


總而言之,將您的index.html基本 href 保留為: <base href="/">然后使用 angular cli 運行ng build --bh ./以使其成為相對路徑,或者將./替換為您需要的任何內容。


更新:

正如上面的示例顯示了如何從命令行執行此操作,這里是如何將其添加到您的 angular.json 配置文件中。

這將用於為本地開發ng serving

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

這是特定於配置構建的配置,例如 prod:

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

官方angular-cli文檔參考了用法。

這就是我們最終要做的事情。

將此添加到 index.html。 它應該是<head>部分中的第一件事

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

然后在app.module.ts文件中,添加{ provide: APP_BASE_HREF, useValue: window['_app_base'] || '/' } { provide: APP_BASE_HREF, useValue: window['_app_base'] || '/' }到提供者列表中,如下所示:

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

根據您 (@sharpmachine) 的回答,我能夠進一步對其進行一些重構,這樣我們就不必破解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 { }

而且, ./shared/common-functions.util.ts包含:

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

在同一個域中構建多個應用程序時,我使用當前工作目錄./

<base href="./">

在旁注中,我使用.htaccess來幫助我在頁面重新加載時路由:

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

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

如果您為 APP_BASE_HREF 不透明令牌提供值,則不必在 index.html 中指定基本標記。

這在生產環境中對我來說很好

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

在 angular4 中,您還可以在 .angular-cli.json 應用程序中配置 baseHref。

在 .angular-cli.json

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

這會將 index.html 中的基本 href 更新為 MY_APP_BASE_HREF_1

ng build --app myapp1

如果您使用的是 Angular CLI 6,則可以使用 angular.json 中的 deployUrl/baseHref 選項(項目 > xxx > 架構師 > 構建 > 配置 > 生產)。 這樣,您可以輕松地為每個項目指定 baseUrl。

通過查看已構建應用程序的 index.html 來檢查您的設置是否正確。

有一個類似的問題,實際上我最終在我的網絡中探測了一些文件的存在。

probePath將是您要檢查的文件的相對 URL(如果您現在位於正確的位置,則為一種標記),例如 '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>

附加組件:如果您想要例如:/users 作為路由器的應用程序基礎,/public 作為資產使用的基礎

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

您可以使用以下方法在 app.module.ts 文件中動態設置基本 href: https ://angular.io/api/common/APP_BASE_HREF

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

@NgModule({
  providers: [{provide: APP_BASE_HREF, useValue: '/my/app'}]
})
class AppModule {}

在 package.json 中將標志 --base-href 設置為相對路徑:

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

我遲到了,但如果你要部署到 IIS,你可以使用重寫規則(我相信它也可以用其他網絡服務器來完成)。

您可以在請求 index.html 時修改傳出響應的內容並動態替換基本 href。 (url 重寫模塊必須安裝到 IIS 中)

以下示例假設您的 index.html 中有<base href="/angularapp/">

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.webServer>
        <rewrite>
            <outboundRules>
                <rule name="Modify base href to current path">
                    <match filterByTags="Base" pattern="^(.*)(/angularapp/)(.*)" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="true">
                        <add input="{REQUEST_URI}" pattern="^(.*)/index.html$"/>
                    </conditions>
                    <action type="Rewrite" value="{C:1}/" />
                </rule>
            </outboundRules>
        </rewrite>
    </system.webServer>
</configuration>

這一直是一個令人頭疼的問題,#location 策略似乎並沒有按照罐子上說的那樣做(似乎這是一個明顯的修復,但遺憾的是不是)所以這對我有用。 感謝大家指點!

請注意,我正在從我的應用程序中調用與應用程序路徑相關的 php 個頁面,這在刷新時出錯,因為文件夾級別太高。 這在下面配置的in2部分中得到解決。

創建一個 web.config 文件並將其放入您的 /src 文件夾中

<configuration>
<system.webServer>
  <rewrite>

<rules>
            <clear />
            <rule name="in2" stopProcessing="true">
                <match url="(.*)(.php)" />
                  <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
                    <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                    <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
                </conditions>
                <action type="Rewrite" url="../{R:0}" />
            </rule>
            <rule name="Angular Routes" stopProcessing="true">
                <match url=".*" />
                <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
                    <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                    <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
                </conditions>
                <action type="Rewrite" url="../myappname/" />
            </rule>

</rules>
  </rewrite>
</system.webServer>

創建一個myappname.html文件,放到/src文件夾下,將兩者都添加到assets下的Angular.json build部分

"assets":{ ["projects/myapp/src/myappname.html","projects/toolbar2/src/web.config"
]

在 index.html

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

var probePath = 'myappname.html';
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 : '/') + "' />");

坦率地說,你的案子對我來說很好!

我正在使用 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>

我只是改變了:

  <base href="/">

對此:

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

不要忘記以 / 結尾

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM