Угловой 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/">
не забывайте заканчивать на /