【发布时间】:2016-07-13 09:08:37
【问题描述】:
我需要向同一服务器发出请求,REST API 在另一个端口上。
如何在不硬编码服务 URL 中的全名的情况下做到这一点?
【问题讨论】:
标签: angular
我需要向同一服务器发出请求,REST API 在另一个端口上。
如何在不硬编码服务 URL 中的全名的情况下做到这一点?
【问题讨论】:
标签: angular
不需要特定于 angular2 的解决方案。您可以使用window.location.hostname 获取当前主机名。
但是请注意,如果您不想直接使用像 window 对象这样的全局变量,您可以提供自己的 Window 对象,然后可以注入。
有关详细信息,请参阅此完整的工作Stackblitz Angular sample。
正如其他人所说,原来的答案不再有效。对于 Angular 6+,您需要提供 Injection Token,以便 window-object 也可以在 AOT-build 中解析。
否则会出现“无法解析所有参数”的错误。
我建议在单独的文件中创建一个WINDOW_PROVIDERS 数组,如下所示:
import { InjectionToken, FactoryProvider } from '@angular/core';
export const WINDOW = new InjectionToken<Window>('window');
const windowProvider: FactoryProvider = {
provide: WINDOW,
useFactory: () => window
};
export const WINDOW_PROVIDERS = [
windowProvider
]
WINDOW_PROVIDERS 常量可以像这样添加到AppModule 中的providers 数组中:
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule
],
providers: [
WINDOW_PROVIDERS, // <- add WINDOW_PROVIDERS here
SampleService,
],
bootstrap: [AppComponent]
})
export class AppModule { }
在SampleService中,window对象可以像这样使用定义的Injection Token注入:
import { Injectable, Inject } from '@angular/core';
import { WINDOW } from '../window.provider';
@Injectable()
export class SampleService {
constructor(@Inject(WINDOW) private window: Window) {
}
getHostname() : string {
return this.window.location.hostname;
}
}
因此,您需要在引导应用程序时为 Window-object 设置提供程序。
import {provide} from 'angular2/core';
bootstrap(..., [provide(Window, {useValue: window})]);
之后,您可以使用窗口对象并像这样访问主机名:
constructor(private window: Window) {
var hostname = this.window.location.hostname;
}
【讨论】:
Can't resolve all parameters 的错误。要完成这项工作,您必须声明一个注入令牌,然后在构造函数中使用它。我将添加一个答案以使其更加明确。
另一种选择是使用来自@angular/platform-browser 的文档。
import {DOCUMENT} from '@angular/platform-browser';
constructor(@Inject(DOCUMENT) private document: Document) {
let url = document.location.protocol +'//'+ document.location.hostname + ':my_port' );
}
【讨论】:
document.origin不一样吗?
DOCUMENT 似乎不是@angular/platform-browser 的documented 的一部分。
DOCUMENT 在@angular/common 中可用
document.location.origin
正如其他人所说,您可以使用window,并使其可注入,从 ng6 及更高版本开始,您需要一个注入令牌。
像这样声明令牌:
export const WINDOW = new InjectionToken('window',
{ providedIn: 'root', factory: () => window }
);
然后在类构造函数中使用:
class Foo {
constructor(@Inject(WINDOW) private window: Window) { }
}
由于Window 是 TypeScript 中的一个接口,如果你不这样做注入,当你构建项目进行生产时,你会得到一个错误:Can't resolve all parameters for <ClassName>。
后来又发了一个:ERROR in : Error: Internal error: unknown identifier undefined。
要更好地理解注入,请阅读 DI 的 angular 文档: https://angular.io/guide/dependency-injection
【讨论】:
document.defaultView获取window对象
Angular 2 最新工作解决方案:
app.module.ts
providers: [
{provide: Window, useValue: window},
...
]
youclass.ts
constructor(
@Inject(Window) private _window: Window
) {
this._baseUrl = `http://${this._window.location.hostname}:3333`;
};
【讨论】:
我使用纯 javascript 和 URL native api 进行 URL 解析:
declare var window: any; // Needed on Angular 8+
const parsedUrl = new URL(window.location.href);
const baseUrl = parsedUrl.origin;
console.log(baseUrl); // this will print http://example.com or http://localhost:4200
【讨论】:
declare var window: any; 那么它就可以工作
我在app.component.ts 中使用以下代码实现了它:
import { Component, OnInit, Inject, Injectable } from '@angular/core';
import { DOCUMENT } from '@angular/platform-browser';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
constructor(@Inject(DOCUMENT) private document: any) { }
ngOnInit() {
this.domain = this.document.location.hostname;
console.log(this.domain);
}
}
这应该会在您的控制台中打印域名。
【讨论】:
import {DOCUMENT} from "@angular/common";
我建议使用window.location,正如其他人所说的那样。
不过,您也可以通过导入 Angular 的通用“Location”库并在可注入对象中使用它来做到这一点,如下所示:
import { Injectable } from '@angular/core';
import { Location } from '@angular/common';
const otherPort = 8000;
@Injectable()
export class ServiceOrComponentName {
constructor(location: Location) {
this.baseUrl = location._platformStrategy._platformLocation._location.protocol +
'//' + location._platformStrategy._platformLocation._location.hostname +
':' + otherPort;
}
}
【讨论】:
我在 Angular 7 上进行了测试,它工作正常
declare var window: any;
console.log (window.location.host); //result lrlucas.github.io > domain github pages
通过 window.location.host 我获得了完整的域
注意:在@Component之前声明window变量
【讨论】:
'ng build --prod=true尝试过你的代码吗?
ng build --prod=true 编译一个angular 项目并用这个命令http-server -o -p 8081 运行服务器,控制台中的结果是127.0.0.1:8081
只需注入 Document。 Angular 有一个 Document 的默认实现。 Document 有一个名为 defaultView 的属性,该属性具有 window 等所有优点。
import { DOCUMENT } from '@angular/common';
import { Inject, Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class HostnameService
{
constructor(
@Inject(DOCUMENT) private document: Document
) { }
getHostname(): string
{
// Remember to use this.document as unscoped document also exists but is not mockable.
return this.document.defaultView.window.location.hostname;
// Or use the location on document.
return this.document.location.hostname;
}
}
其他地方不需要设置。
【讨论】: