【问题标题】:Get domain name for service in Angular2在Angular2中获取服务的域名
【发布时间】:2016-07-13 09:08:37
【问题描述】:

我需要向同一服务器发出请求,REST API 在另一个端口上。

如何在不硬编码服务 URL 中的全名的情况下做到这一点?

【问题讨论】:

    标签: angular


    【解决方案1】:

    不需要特定于 angular2 的解决方案。您可以使用window.location.hostname 获取当前主机名。

    但是请注意,如果您不想直接使用像 window 对象这样的全局变量,您可以提供自己的 Window 对象,然后可以注入。

    有关详细信息,请参阅此完整的工作Stackblitz Angular sample

    Angular 6+ 的更新答案

    正如其他人所说,原来的答案不再有效。对于 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;
        }
    }
    

    Angular 2 的原始答案

    因此,您需要在引导应用程序时为 Window-object 设置提供程序。

    import {provide} from 'angular2/core';
    bootstrap(..., [provide(Window, {useValue: window})]);
    

    之后,您可以使用窗口对象并像这样访问主机名:

    constructor(private window: Window) {
       var hostname = this.window.location.hostname;
    }
    

    【讨论】:

    • 使用自己的 Window 对象与使用全局常量相比有什么优势?谢谢
    • 这将不再适用于 Angular 6。您将收到Can't resolve all parameters 的错误。要完成这项工作,您必须声明一个注入令牌,然后在构造函数中使用它。我将添加一个答案以使其更加明确。
    • 角度万能的呢?这仍在使用 window_providers?
    • 这将因“ng build --prod=true”而失败。为了解决这个问题,useFactory 需要是一个正常的函数。
    • @bubble (and others) 你为什么要通过注入来做到这一点的答案是:单元测试。例如,如果您想对您的方法从该位置正确构造一个 URI(例如原点 + 路径名 + 新路径)进行单元测试,然后打开一个指向该路径的新窗口......您需要提供一个假的:stackoverflow.com/a/40320802/5753629
    【解决方案2】:

    另一种选择是使用来自@angular/platform-b​​rowser 的文档。

    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-browserdocumented 的一部分。
    • 错误:“@angular/platform-b​​rowser/platform-b​​rowser”没有导出的成员“文档”
    • DOCUMENT@angular/common 中可用
    • 或者你可以使用document.location.origin
    【解决方案3】:

    正如其他人所说,您可以使用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 &lt;ClassName&gt;。 后来又发了一个:ERROR in : Error: Internal error: unknown identifier undefined

    要更好地理解注入,请阅读 DI 的 angular 文档: https://angular.io/guide/dependency-injection

    【讨论】:

    • 也可以通过document.defaultView获取window对象
    【解决方案4】:

    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`;
    };
    

    【讨论】:

    • 这对我有用。 @angular/common 中的定位服务没用
    【解决方案5】:

    我使用纯 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
    

    【讨论】:

    • 这是解决问题的最简洁和最轻量级的答案。非常感谢。
    • 这不适用于 Angular 8,但是如果你使用 declare var window: any; 那么它就可以工作
    【解决方案6】:

    我在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);
        }
    }
    

    这应该会在您的控制台中打印域名。

    【讨论】:

    • 这对我有用,但是我的 linter 显示了一个已弃用的警告并建议这样做:import {DOCUMENT} from "@angular/common";
    【解决方案7】:

    我建议使用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;
      }
    }
    

    【讨论】:

    • 我认为这不是最佳做法,因为您依赖私有属性,将来可能会发生变化。
    • 我同意。然而,令人沮丧的是,数据就在那里,却无法正确访问。
    【解决方案8】:

    我在 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尝试过你的代码吗?
    • 是的@James Poulose,用ng build --prod=true 编译一个angular 项目并用这个命令http-server -o -p 8081 运行服务器,控制台中的结果是127.0.0.1:8081
    【解决方案9】:

    只需注入 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;
    
      }
    }
    

    其他地方不需要设置。

    【讨论】:

      猜你喜欢
      • 2011-11-04
      • 1970-01-01
      • 2022-12-18
      • 2010-12-08
      • 2018-05-08
      • 1970-01-01
      • 2014-02-16
      • 2020-10-27
      • 2012-11-26
      相关资源
      最近更新 更多