Angular 2+ - 动态设置基本href
Posted
技术标签:
【中文标题】Angular 2+ - 动态设置基本href【英文标题】:Angular 2+ - Set base href dynamically 【发布时间】:2016-11-01 22:42:32 【问题描述】:我们有一个为客户端使用 Angular 2 的企业应用程序。我们的每个客户都有自己独特的网址,例如:https://our.app.com/customer-one
和 https://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>
...
不幸的是,我们还没有新的想法。任何帮助都会很棒。
【问题讨论】:
你有没有尝试过使用APP_BASE_HREF?我不太确定它将如何实现,但它似乎是有用的...... 当然这也取决于您当前使用的路由器版本。你在路由器版本 3.0.0-alpha.x 上吗? 我正在使用“@angular/router”:“3.0.0-alpha.7” Angular 7 - 2018 年 11 月。这仍然是一个问题。当前的答案提供了部分解决方案。在 Angular 模块中做事为时已晚。当您的索引 HTML 被提供时,它需要知道从哪里提取脚本。我看到的方式只有 2 种方式 - 使用 asp\php\whatever 为 index.html 提供动态 basehref 内容。或在 index.html 文件上使用本机 javascript 在 DOM 内容变为 Angular 之前对其进行更改。两者都是对一个共同问题的糟糕解决方案。伤心。 有人也可以回答我的问题吗? ***.com/questions/53757931/… 【参考方案1】:您可以使用以下方法在 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
【讨论】:
【参考方案2】:在 package.json 中将标志 --base-href 设置为相对路径:
"script":
"build": "ng build --base-href ./"
【讨论】:
【参考方案3】:我刚刚换了:
<base href="/">
到这里:
<base href="/something.html/">
别忘了以 / 结尾
【讨论】:
【参考方案4】:有一个类似的问题,实际上我最终在我的网络中探测了一些文件的存在。
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>
【讨论】:
【参考方案5】:附加组件:如果您想要例如:/users 作为路由器的应用程序基础,/public 作为资产使用的基础
$ ng build -prod --base-href /users --deploy-url /public
【讨论】:
【参考方案6】:此处标记的答案没有解决我的问题,可能是不同的角度版本。我能够在终端/shell 中使用以下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:
"configurations":
"Prod":
"fileReplacements": [
"replace": src/environments/environment.ts",
"with": src/environments/environment.prod.ts"
],
"baseHref": "./productionurl/",
officialangular-cli
文档涉及使用情况。
【讨论】:
此解决方案需要为每个客户构建,这可能无法解决 OP 的问题。 @MaximeMorin 以我目前的经验来看,./
适用于所有地点。所以实际上我认为你不必为每个客户构建。
@Zze 我对./
的体验非常不同。它一直有效,直到用户导航到路线并点击浏览器的刷新按钮或按键。此时,我们的重写处理调用,提供索引页面,但浏览器假定./
是当前路由而不是 Web 应用程序的根文件夹。我们通过设置基本 href 的动态(.aspx、.php、.jsp 等)索引解决了 OP 的问题。
在构建过程中使用--prod
不会改变你的base href
值,你不应该在这里谈论它。 --prod
告诉 angular-cli
使用 environment.prod.ts
文件而不是 environments
文件夹中的默认文件 environment.ts
Angular 7.1:Unknown option: '--bh'
。 --base-href
工作。【参考方案7】:
坦率地说,你的情况对我来说很好!
我正在使用 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>
【讨论】:
这个解决方案对你有用吗?我正面临这个问题。能否请您也回复我的帖子。 ***.com/questions/53757931/… 请避免使用 document.write(): developers.google.com/web/updates/2016/08/…【参考方案8】:如果您使用的是 Angular CLI 6,则可以使用 angular.json 中的 deployUrl/baseHref 选项(项目 > xxx > 架构师 > 构建 > 配置 > 生产)。这样,您可以轻松地为每个项目指定 baseUrl。
通过查看已构建应用的 index.html 来检查您的设置是否正确。
【讨论】:
这需要针对每个环境进行不同的构建,包括所有影响。【参考方案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"
,
],
这会将 index.html 中的基本 href 更新为 MY_APP_BASE_HREF_1
ng build --app myapp1
【讨论】:
这也需要为每个app做一个build。【参考方案10】:这在生产环境中对我来说很好
<base href="/" id="baseHref">
<script>
(function()
document.getElementById('baseHref').href = '/' + window.location.pathname.split('/')[1] + "/";
)();
</script>
【讨论】:
此解决方案在 IIS 中设置多个 VD 时存在很大限制。它会导致重复加载块。 使用硬编码的 base-href 并调用http://my.app.com/app1
将 url 更改为 http://my.app.com/app1/
(最后 / )这个解决方案在 http://my.app.com/app1
的情况下也适用于我,因为更改为 http://my.app.com/app1/
- 否则无法加载资源。【参考方案11】:
将现有的answer 简化为@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 中指定基本标记。
【讨论】:
【参考方案12】:根据您 (@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;
【讨论】:
我已将 myapp 部署到子文件夹。我的网址现在看起来像这样:http://localhost:8080/subfolder/myapp/#/subfolder/myroute
这是你的样子吗?你知道如何去掉 # 之后的子文件夹,让它变成http://localhost:8080/subfolder/myapp/#/myroute
吗?
哦。我认为 href base 只有 LocationStrategy 才需要。就我而言,我使用的是 HashLocationStrategy。所以我什至不需要设置它。您是否编写了特殊代码来处理 LocationStrategy 的刷新?
是的,base href
仅适用于 LocationStrategy
AFAIK。至于使用 LocationStrategy 编写特殊代码来处理刷新,不确定您的确切意思。您是在问,如果我的“基本 href”在我的应用程序中的活动期间发生变化怎么办?然后,是的,我不得不做一件像window.location.href = '/' + newBaseHref;
这样需要更改的肮脏事情。我对此并不感到骄傲。此外,为了提供更新,我在我的应用程序中放弃了这些黑客解决方案,因为它已成为我的设计问题。路由器参数工作得很好,所以我坚持使用它。
你的appRoutingProvider
是什么样的,克里希南?我看到接受的答案是一样的;也许你只是复制了他的providers
,但如果没有,你能给我一个样本或描述它的用途吗? documentation only imports
routing modules,它不使用任何与路由相关的提供程序(据我所知)
@Krishnan 以下是我必须使用 nginx 做的事情:location /subfolder/myapp/ try_files $uri /subfolder/myapp/index.html; location /subfolder2/myapp/ try_files $uri /subfolder2/myapp/index.html;
【参考方案13】:
当在同一个域中构建多个应用程序时,我使用当前工作目录./
:
<base href="./">
附带说明,我使用.htaccess
来协助我在页面重新加载时路由:
RewriteEngine on
RewriteCond %REQUEST_FILENAME !-f
RewriteRule .* index.html [L]
【讨论】:
非常感谢您提供.htaccess
文件
这个答案不正确,它不适用于/your-app/a/b/c 等路由。如果您从这样的路由刷新页面,Angular 将在 /your-app/a/b/ 下查找运行时、polyfills 和主 JS 文件和样式 CSS 文件。他们显然不在那个位置,而是在 /your-app/
@toongeorges 这个答案是大约两年前写的,使用的配置文件由 Apache Web 服务器软件检测并执行,以处理页面重新加载时的路由。你说这个解决方案不正确并且不起作用是一种误导,但你的意思是你无法弄清楚如何让它与你的配置一起工作。
我忽略了 Apache 重写规则,我对此知之甚少,不能说这在 Apache 上不起作用,所以我可能是错的,你的答案可能是正确的。尽管在任何情况下我都更喜欢不需要您修改服务器配置的解决方案,因为这里已经给出了多个答案,因为这使得应用程序可以跨不同的服务器移植。
使用./
会中断路由到多级深度的地址。例如http://localhost:4200/foo/bar
.【参考方案14】:
这就是我们最终要做的事情。
将此添加到 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
【讨论】:
错误 TS7017:元素隐式具有“任何”类型,因为类型“窗口”没有索引签名。useValue: (window as any) ['_app_base'] || '/'
helps
对于最新的ng2真的不行,有解决办法吗? (加载错误的脚本路径,然后加载好的脚本路径,但不在移动设备上)
将其添加为下面的答案,因为内容长度太长,无法发表评论。
@Amit 请在下面查看我的答案,以便在最新的 ng2 中轻松解决。
您是如何解决其他文件的问题的。我的浏览器正在尝试加载localhost:8080/main.bundle.js,但因为我的 contextPath 不同而无法加载? (应该是获取localhost:8080/hello/main.bundle.js.)以上是关于Angular 2+ - 动态设置基本href的主要内容,如果未能解决你的问题,请参考以下文章
打字稿 | JavaScript | Angular 2:动态设置@HostListener 参数