Угловой 2 / 4 / 5 - динамически установить основание

У нас есть корпоративное приложение, которое использует Angular 2 для клиента. Каждый из наших клиентов имеет свой уникальный URL, например: https://our.app.com/customer-one а также https://our.app.com/customer-two, В настоящее время мы можем установить <base href...> динамически используя document.location, Так что пользователь нажимает 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>

...

К сожалению, мы свежие идеи. Любая помощь будет потрясающей.

16 ответов

Решение

Вот что мы в итоге сделали.

Добавьте это в 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'] || '/' } к списку провайдеров, вот так:

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

Отмеченный ответ здесь не решил мою проблему, возможно, различные угловые версии. Я смог достичь желаемого результата с помощью следующих angular cli команда в терминале / оболочке:

ng build --base-href /myUrl/

ng build --bh /myUrl/ или же ng build --prod --bh /myUrl/

Это меняет <base href="/"> в <base href="/myUrl/"> только в сборочной версии, которая идеально подходила для нашего изменения среды между разработкой и производством. Самое приятное, что кодовая база не требует изменений с помощью этого метода.


Подводя итог, оставьте свой index.html базовая ссылка как: <base href="/"> затем беги ng build --bh ./ с угловым кли, чтобы сделать его относительным путем, или заменить ./ с тем, что вам нужно.

Официальный angular-cli документация, касающаяся использования.

Основываясь на вашем (@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 { }

Вам не нужно указывать базовый тег в вашем index.html, если вы предоставляете значение для непрозрачного токена APP_BASE_HREF.

Это хорошо работает для меня в среде Prod

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

В angular4 вы также можете настроить baseHref в приложениях.angular-cli.json.

в.angular-cli.json

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

это обновит базовый href в index.html до MY_APP_BASE_HREF_1

ng build --app myapp1

У меня была похожая проблема, на самом деле я обнаружил, что в моей сети есть какой-то файл.

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>

Если вы используете Angular CLI 6, вы можете использовать параметры deployUrl/baseHref в angular.json (проекты> xxx > architect > build > configurations > production). Таким образом, вы можете легко указать baseUrl для каждого проекта.

Проверьте правильность настроек, посмотрев на index.html встроенного приложения.

Дополнения: Если вы хотите, например, для: /users в качестве базы приложения для маршрутизатора и /public в качестве базы для использования ресурсов

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

Вы можете установить базовый href динамически в файле app.module.ts, используя это: 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 {}

Это была огромная головная боль, стратегия #location, похоже, не делает того, что написано на банке (казалось, что это было исправление obvios, но, к сожалению, нет), так что вот что сработало для меня. Спасибо всем за указатели!

Примечание. Я вызываю 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. Добавьте оба файла в раздел сборки Angular.json под активами.

      "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 : '/') + "' />");

В package.json установите флаг --base-href на относительный путь:

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

Я опаздываю на шоу, но вы можете использовать правило перезаписи, если вы развертываете в IIS (я уверен, что это можно сделать и с другими веб-серверами).

Вы можете изменить содержимое исходящего ответа при запросе index.html и динамически заменить базовый href. (модуль перезаписи URL должен быть установлен в IIS)

В следующем примере предполагается, что у вас есть <base href="/angularapp/">в вашем index.html

      <?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>

Откровенно говоря, ваше дело прекрасно работает для меня!

Я использую 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/">

не забывайте заканчивать на /

Другие вопросы по тегам