Angular 2/4/5 - 动态设置基本href

sha*_*ine 107 angular

我们有一个企业应用程序,它为客户端使用Angular 2.我们每个客户都有自己独特的网址,例如:https://our.app.com/customer-onehttps://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...>设置为get /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>

...
Run Code Online (Sandbox Code Playgroud)

不幸的是,我们的想法很新鲜.任何帮助都会很棒.

Zze*_*Zze 139

这里明显的答案并没有解决我的问题,可能是不同的角度版本.我能够angular cli在终端/ shell中使用以下命令实现所需的结果:

ng build --base-href /myUrl/

ng build --bh /myUrl/ 要么 ng build --prod --bh /myUrl/

这改变了<base href="/"><base href="/myUrl/">唯一一款内置版本这是非常适合我们环境的开发和生产之间的变化.最好的部分是没有代码库需要使用此方法更改.


总而言之,将您的index.html基础href 保留为:<base href="/">然后ng build --bh ./使用angular cli 运行以使其成为相对路径,或者将其替换为./您需要的任何内容.


更新:

如上例所示,如何从命令行执行此操作,以下是如何将其添加到angular.json配置文件中.

这将用于所有ng serving本地开发

"architect": {
    "build": {
      "builder": "@angular-devkit/build-angular:browser",
      "options": {
        "baseHref": "/testurl/",
Run Code Online (Sandbox Code Playgroud)

这是配置构建的特定配置,例如prod:

"configurations": {
   "Prod": {
     "fileReplacements": [
        {
          "replace": src/environments/environment.ts",
          "with": src/environments/environment.prod.ts"
        }
      ],
      "baseHref": "./productionurl/",
Run Code Online (Sandbox Code Playgroud)

涉及用法的官方 angular-cli文档.

  • 该解决方案需要按客户构建,这可能无法解决OP的问题. (29认同)
  • @Zze我对`./`的体验非常不同.它一直有效,直到用户导航到路线并点击浏览器的刷新按钮.此时,我们的重写处理调用,提供索引页面,但浏览器假定`./`是当前路由而不是Web应用程序的根文件夹.我们用动态(.aspx,.php,.jsp等)索引解决了OP的问题,该索引设置了基本的href. (8认同)
  • 在构建过程中使用 `--prod` 不会改变你的 `base href` 值,你不应该在这里谈论它。`--prod` 告诉 `angular-cli` 使用 `environment.prod.ts` 文件而不是 `environments` 文件夹中的默认文件 `environment.ts` (3认同)
  • **Angular 7.1:`未知选项:'--bh'`**。`--base-href` 有效。 (2认同)

sha*_*ine 52

这就是我们最终做的事情.

将其添加到index.html.它应该是该<head>部分的第一件事

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

然后在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 { }
Run Code Online (Sandbox Code Playgroud)

  • 您如何解决其他文件的问题。我的浏览器正在尝试加载http:// localhost:8080 / main.bundle.js,但是不能,因为我的contextPath不同吗?(它应该正在获取http:// localhost:8080 / hello / main.bundle.js。) (3认同)

Kri*_*nan 30

基于你的(@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 { }
Run Code Online (Sandbox Code Playgroud)

并且,./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;
}
Run Code Online (Sandbox Code Playgroud)


Dae*_*rik 25

./在同一个域中构建多个应用程序时,我使用当前工作目录:

<base href="./">
Run Code Online (Sandbox Code Playgroud)

在旁注,我.htaccess用来协助我的页面重新加载路由:

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* index.html [L]
Run Code Online (Sandbox Code Playgroud)

  • 这个答案是不正确的,它不适用于/ your-app/a/b/c等路由.如果从这样的路径刷新页面,Angular将在/ your-app/a/b /下查找运行时,polyfill和主要JS文件以及样式CSS文件.他们显然不在那个位置,但在/ your-app /下 (7认同)
  • 非常感谢`.htaccess`文件 (2认同)
  • @toongeorges这个答案大约两年前使用Apache Web Server软件检测和执行的配置文件编写,以处理页面重新加载的路由.你说这个解决方案不正确并且不起作用会产生误导,但你的意思是你无法弄清楚如何让它与你的配置一起工作. (2认同)

Kar*_*ang 15

现有的简化答案@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 { }
Run Code Online (Sandbox Code Playgroud)

如果要为APP_BASE_HREF opaque标记提供值,则不必在index.html中指定基本标记.


Avi*_*kar 9

在生产环境中这对我来说很好

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

  • 此解决方案对 IIS 中的多个 VD 设置有很大的限制。它会导致块的重复加载。 (2认同)

小智 9

在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"
         },
    ],
}
Run Code Online (Sandbox Code Playgroud)

这会将index.html中的基本href更新为MY_APP_BASE_HREF_1

ng build --app myapp1
Run Code Online (Sandbox Code Playgroud)

  • 这也需要为每个应用构建一个版本。 (3认同)

Ron*_*rze 6

有一个类似的问题,实际上我最终探测了我的网络中是否存在某个文件。

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>
Run Code Online (Sandbox Code Playgroud)


小智 5

如果使用的是Angular CLI 6,则可以使用angular.json中的deployUrl / baseHref选项(项目> xxx>架构师>构建>配置>生产)。这样,您可以轻松地为每个项目指定baseUrl。

通过查看内置应用程序的index.html来检查设置是否正确。

  • 这就要求每个环境都有一个不同的版本,及其所有含义。 (6认同)