【问题标题】:How do I set the baseUrl for Angular HttpClient?如何为 Angular HttpClient 设置 baseUrl?
【发布时间】:2017-08-17 12:52:11
【问题描述】:

我没有在documentation 中找到为 HTTP 请求设置基本 API URL 的方法。 Angular HttpClient 可以做到这一点吗?

【问题讨论】:

  • 你可以创建一个interceptor 来更新你想要的任何基础的url。
  • 在这种情况下使用拦截器不是开销吗?
  • 如果你只想改变这个是的,它可能是。另一种选择是使用一个简单的函数 getApiUrl() 来进行所需的任何转换,例如添加基本路径。
  • 或者创建一个派生自XHRBackend 的类,并使用适当的基本 url 创建连接。每种方法都有优缺点,我不知道有任何“更简单”的方法来提供这种方法。
  • 我个人使用拦截器,但建议添加其他功能,例如为所有请求设置标头。

标签: angular angular-httpclient


【解决方案1】:

使用新的 HttpClient 拦截器。

创建一个实现HttpInterceptor的适当注入:

import {Injectable} from '@angular/core';
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from '@angular/common/http';
import {Observable} from 'rxjs/Observable';

@Injectable()
export class APIInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    const apiReq = req.clone({ url: `your-api-url/${req.url}` });
    return next.handle(apiReq);
  }
}

HttpInterceptor 可以克隆请求并根据需要更改它,在这种情况下,我为所有 http 请求定义了一个默认路径。

为 HttpClientModule 提供以下配置:

providers: [{
      provide: HTTP_INTERCEPTORS,
      useClass: APIInterceptor,
      multi: true,
    }
  ]

现在您的所有请求都将以your-api-url/开头

【讨论】:

  • 这太棒了!但有一件事,你不需要在这里使用 Injectable 装饰器,它只有在你想注入一些东西到装饰类时才需要。
  • 如果您希望不同的 HttpClients 使用不同的基本 url,您如何管理呢?注射剂打开的请求中的某种标记,多个注射器。在我看来一点也不优雅。
  • 看到这段代码我哭了。为什么我们不能只创建一个具有baseUrl 属性的客户端实例,而不是这种类似中间件的解决方案,这种解决方案对于这样一个简单的用例来说是最重要的
  • 我是唯一一个看到req.clone 开销的人吗? HttpRequest 似乎是不可变的,所以对于大请求,我想会增加大量的开销处理吗?我知道它看起来很整洁,但它不是增加了无用的再处理吗?我错过了什么吗?仅供参考:我是前台菜鸟
  • 这个问题是它会改变所有的请求,而不仅仅是对 api 的请求。例如,angular-svg-icon 之类的东西使用了 HttpClient 并且不再工作了。
【解决方案2】:

根据TheUnreal的非常有用的回答,可以编写拦截器通过DI获取base url:

@Injectable()
export class BaseUrlInterceptor implements HttpInterceptor {

    constructor(
        @Inject('BASE_API_URL') private baseUrl: string) {
    }

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

        const apiReq = request.clone({ url: `${this.baseUrl}/${request.url}` });
        return next.handle(apiReq);
    }
}

BASE_API_URL可以由应用模块提供:

providers: [
    { provide: "BASE_API_URL", useValue: environment.apiUrl }
]

其中environment是CLI在生成项目时自动创建的对象:

export const environment = {
  production: false,
  apiUrl: "..."
}; 

【讨论】:

  • 你在哪里设置BASE_API_URL
  • @emaillenin - 因为评论不止一条,所以我在答案中添加了信息。基本上,该值是“全局”提供的。
  • @Alexei 如果我们需要使用 2 个不同的 BASE_API_URL 怎么办?我的意思是我们有一个项目,它使用 2 个不同基础的 API 服务器
  • @user1325696 - 您可以在environment 对象中定义两个属性并在应用程序模块中提供两个值(我假设不同的组件使用它们中的任何一个,因此注入该特定组件所需的任何内容都是有意义的组件)。
  • 以及如何在此处调用该环境和其他设置文档:angular.io/guide/build
【解决方案3】:

为什么不创建一个具有可配置 baseUrl 的 HttpClient 子类?这样,如果您的应用程序需要与多个服务通信,您可以为每个服务使用不同的子类,或者创建单个子类的多个实例,每个实例具有不同的配置。

@Injectable()
export class ApiHttpClient extends HttpClient {
  public baseUrl: string;

  public constructor(handler: HttpHandler) {
    super(handler);

    // Get base url from wherever you like, or provision ApiHttpClient in your AppComponent or some other high level
    // component and set the baseUrl there.
    this.baseUrl = '/api/';
  }

  public get(url: string, options?: Object): Observable<any> {
    url = this.baseUrl + url;
    return super.get(url, options);
  }
}

【讨论】:

  • 其他任何想要这样做的人请不要这样做。 HttpClient 是一个“Final”类,Angular 不建议扩展“Final”类,因为它的内部实现可能会改变。更多信息在这里:github.com/angular/angular/blob/13.1.1/docs/…
【解决方案4】:

每个关注 Alexei 的人都无法像我一样工作 - 这是因为您还必须将此元素添加到 providers 数组中

{
  provide: HTTP_INTERCEPTORS,
  useClass: BaseUrlInterceptor,
  multi: true
}

很遗憾,我的声誉太低,无法在他的回答中添加评论。

【讨论】:

  • 我投了赞成票来帮助你,我的朋友。
  • @BraianSilva 谢谢哥们,你真的是我现在可以发表评论的原因!
【解决方案5】:

摘自 Visual Studio 2017 asp.net core webapi angular 示例应用程序。

在 Main.ts 中包含以下行

export function getBaseUrl() {
  return document.getElementsByTagName('base')[0].href;
}

const providers = [
  { provide: 'BASE_URL', useFactory: getBaseUrl, deps: [] }
];

在你的组件中

  constructor(http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
    http.get<WeatherForecast[]>(baseUrl + 'api/SampleData/WeatherForecasts').subscribe(result => {
      this.forecasts = result;
    }, error => console.error(error));
  }

我完整的 main.ts 代码如下所示

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

export function getBaseUrl() {
  return document.getElementsByTagName('base')[0].href;
}

const providers = [
  { provide: 'BASE_URL', useFactory: getBaseUrl, deps: [] }
];

if (environment.production) {
  enableProdMode();
}

platformBrowserDynamic()
  .bootstrapModule(AppModule)
  .catch(err => console.error(err));

我的组件代码如下所示

import { Component, Inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'fetch-weather',
  templateUrl: './weather.component.html',
  styleUrls: ['./weather.component.scss']
})

export class WeatherComponent {
  public forecasts: WeatherForecast[];

  constructor(http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
    http.get<WeatherForecast[]>(baseUrl + 'api/SampleData/WeatherForecasts').subscribe(result => {
      this.forecasts = result;
    }, error => console.error(error));
  }
}

interface WeatherForecast {
  dateFormatted: string;
  temperatureC: number;
  temperatureF: number;
  summary: string;
}

【讨论】:

  • 这是一个非常棒的解决方案。特别是因为它可以使用 angular 已经包含的 --base-href 功能 - 使得在子文件夹中托管 api + angular 应用程序变得如此容易。
【解决方案6】:

你不一定需要一个带有 HttpClientbase URL,文档说你只需要指定请求的 api 部分,如果你正在调用同一台服务器很简单:

this.http.get('/api/items').subscribe(data =&gt; {...

但是,如果您需要或想要,您可以指定一个基本 URL。

我有 2 条建议:

1。具有静态类属性的辅助类。

export class HttpClientHelper {

    static baseURL: string = 'http://localhost:8080/myApp';
}


this.http.get(`${HttpClientHelper.baseURL}/api/items`); //in your service class

2。具有类属性的基类,因此任何新服务都应扩展它:

export class BackendBaseService {

  baseURL: string = 'http://localhost:8080/myApp';

  constructor(){}
}

@Injectable()
export class ItemsService extends BackendBaseService {

  constructor(private http: HttpClient){  
    super();
  }
      
  public listAll(): Observable<any>{    
    return this.http.get(`${this.baseURL}/api/items`);
  }

}

【讨论】:

    【解决方案7】:

    我认为没有默认方法可以做到这一点。做 HttpService 并且在里面你可以定义你的默认 URL 的属性,并使用你的属性 URL 来调用 http.get 和其他方法。然后注入HttpService而不是HttpClient

    【讨论】:

    • 我是为Http服务做的,但希望HttpClient更聪明一点
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-13
    • 2012-07-26
    • 1970-01-01
    • 2020-06-16
    • 2019-06-09
    • 2020-01-21
    • 2021-08-15
    相关资源
    最近更新 更多