Set base url for angular 2 http requests

混江龙づ霸主 提交于 2019-11-27 06:52:43
vegazz

For angular 4.3+ and @angular/common/http

It's simple with interceptors

@Injectable()
export class ExampleInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const url = 'http://myurl.com';
    req = req.clone({
      url: url + req.url
    });
    return next.handle(req);
  }
}

app.module.ts

import { NgModule } from '@angular/core';
import { Injectable } from '@angular/core';
import { HttpClientModule, HttpRequest, HTTP_INTERCEPTORS } from '@angular/common/http';

@NgModule({
  declarations: [
    AppComponent,
    ...
  ],
  imports: [
    BrowserModule,
    HttpClientModule,
    ...
  ],
  providers: [
    AppComponent,
    { provide: HTTP_INTERCEPTORS, useClass: ExampleInterceptor, multi: true }
  ],
  bootstrap: [ AppComponent ]
})
export class AppModule { }

EDIT: HttpClient and HttpInterceptor are introduced in Angular 4.3

corolla

UPDATE: See @vegazz answer for Angular 4.

For Angular 2.2.1, the following should prefix web api base url and represents a smaller footprint:

import {Request, XHRBackend, XHRConnection} from '@angular/http';

@Injectable()
export class ApiXHRBackend extends XHRBackend {
    createConnection(request: Request): XHRConnection {
        if (request.url.startsWith('/')){
            request.url = 'http://localhost:3000' + request.url;     // prefix base url
        }
        return super.createConnection(request);
    }
}

Inject into providers in app.module.ts:

providers: [
    { provide: XHRBackend, useClass: ApiXHRBackend }
  ]

Usage example:

this._http.post('/api/my-route', {foo: 'bar'})
            .map<MyResponse>(res => res.json())

It seems to cover all methods (GET, PUT, POST, ...)

yeelan

For Angular2 Version 2.2 (As for Dec 2016)

Angular from RC5 mark HTTP_PROVIDERS as deprecated and trying to move things into @NgModule, the above solution is not really applicable, so as their documentation. I cross referred several other answers and found my way to implement base url, hope this might be helpful to someone else.

The basic idea is, instead of doing things in bootstrap, we move things to AppModule.

app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpModule, RequestOptions } from '@angular/http';


import { CustomRequestOptions } from './customrequest.options';

@NgModule({
  declarations: [
    AppComponent,
    ...
  ],
  imports: [
    BrowserModule,
    HttpModule,
    ...
  ],
  providers: [
    { provide: RequestOptions, useClass: CustomRequestOptions }
  ],
  bootstrap: [ AppComponent ]
})

And move CustomRequestOptions into a separate injectable service

import { Injectable } from '@angular/core';
import { BaseRequestOptions, RequestOptions, RequestOptionsArgs } from '@angular/http';

@Injectable()
export class CustomRequestOptions extends BaseRequestOptions {
  merge(options?:RequestOptionsArgs):RequestOptions {
    options.url = 'http://localhost:9080' + options.url;
    return super.merge(options);
  }
}

Edit for request method other than GET.

If you are trying to send request type other than GET, the previous method fails to inject the baseurl into the request. This is because Angular2 generate new RequestOptions other than this._defaultOptions whose merge method isn't being override by our CustomRequestOptions. (See the source code here).

So instead of returning super.merge(...) in the last step of CustomRequestOptions merge method, I generated a new instance of CustomRequestOptions to ensure the following operation will still work.

import { Injectable } from '@angular/core';
import { RequestOptions, RequestOptionsArgs } from '@angular/http';

@Injectable()
export class CustomRequestOptions extends RequestOptions {
  merge(options?: RequestOptionsArgs): RequestOptions {
    if (options !== null && options.url !== null) {
      options.url = 'http://localhost:9080' + options.url;
    }
    let requestOptions = super.merge(options)
    return new CustomRequestOptions({
      method: requestOptions.method,
      url: requestOptions.url,
      search: requestOptions.search,
      headers: requestOptions.headers,
      body: requestOptions.body,
      withCredentials: requestOptions.withCredentials,
      responseType: requestOptions.responseType
    });
  }
}

And this works for POST, PUT, DELETE method as well. Hope this is helpful.

Adrian Sobiczewski

In Angular 2.0.0-beta.6 You can achieve this by overriding 'merge'

import {BaseRequestOptions, RequestOptions, RequestOptionsArgs} from 'angular2/http';

export class ApRequestOptions extends BaseRequestOptions {

  merge(options?:RequestOptionsArgs):RequestOptions {
    options.url = 'http://10.7.18.21:8080/api' + options.url;
    return super.merge(options);
  }

}
Thierry Templier

After having a look at code sources for BaseRequestOptions, RequestOptions and Http classes:

It appears that the url property corresponds to the default URL but not a prefix for URLs.

To implement your use case, I would suggest to put a service in front of the http object and inject then the service. Something like that:

import {Injectable} from '@angular/core';
import {Http} from '@angular/http';

@Injectable()
export class HttpClient {
  http: Http;
  urlPrefix: string;

  constructor(http: Http) {
    this.http = http;
    this.urlPrefix = 'http://...';
  }

  get(url) {
    return this.http.get(this.urlPrefix + url);
  }

  post(url, data) {
    return this.http.post(this.urlPrefix + url, data);
  }
}

And

import {HttpClient} from './http-client';

export classMyComponent {
  constructor(httpClient: HttpClient) {
    this.httpClient = httpClient;
  }

  handleSomething() {
    this.httpClient.post(url, data)
    ).subscribe(...);
  }
}

That said such could perhaps be contributed to Angular2 itself ;-)

Hope it helps you, Thierry

istibekesi

Different approach: during development running your app in localhost, consider configuring a proxy instead.

proxy.conf.json

{
   "/api/**": {
      "target": "http://10.7.18.21:8080/",
      "secure": false,
      "logLevel": "debug"
   }
}

More: link

Günter Zöchbauer
import {LocationStrategy} from 'angular2/router';

constructor(private locationStrategy:LocationStrategy) {
  console.log(locationStrategy.prepareExternalUrl('xxx'));
}

See also https://github.com/angular/angular/blob/1bec4f6c6135d7aaccec7492d70c36e1ceeaeefa/modules/angular2/test/router/path_location_strategy_spec.ts#L88

Jinseoung Lee

For currently user, here is really working example in angular 2.4.8

here is the code for why split and chained BaseCommonRequestOptions and CommonRequestOptions.

import { BaseRequestOptions, Headers, RequestOptions, RequestOptionsArgs } from '@angular/http';
import { Injectable } from '@angular/core';

@Injectable()
export class BaseCommonRequestOptions extends BaseRequestOptions {

  merge(options?: RequestOptionsArgs): RequestOptions {
    return new CommonRequestOptions(super.merge(extracted(options)));
  }
}

/**
 * for inner merge when using post put patch delete...others method
 */
export class CommonRequestOptions extends RequestOptions {
  merge(options?: RequestOptionsArgs): RequestOptions {
    return new RequestOptions(super.merge(extracted(options)));
  }
}

/**
 * inject default values
 *
 * @param options
 * @returns {RequestOptionsArgs}
 */
export function extracted(options: RequestOptionsArgs) {
  console.log(options);
  if (!validUrl(options.url)) {
    options.url = 'http://localhost:3000' + (options.url ? options.url : "");
  }
  // use default header application/json, if content-type header was empty.
  if (options.headers != null) {
    let contentType = options.headers.get('content-type');
    if (contentType == null || contentType == '') {
      options.headers.append('content-type', 'application/json');
    }
  } else {
    options.headers = new Headers({ 'content-type': 'application/json' });
  }

  return options;
}

/**
 * validate url
 *
 * @param url
 * @returns {boolean}
 */
export function validUrl(url: string) {
  return /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/.test(url);
}

create a .ts file

import { Injectable } from '@angular/core';
import {Request, XHRBackend, XHRConnection} from '@angular/http';


    @Injectable()
    export class ApiXHRBackend extends XHRBackend {
    createConnection(request: Request): XHRConnection {
    if (request.url.startsWith('/api')){
    var url=request.url.replace("/api", "");
    request.url = 'http://localhost:8080' + url; // prefix base url
    }
    return super.createConnection(request);
    }

}

Then in app.module.ts

import { ApiXHRBackend } from './guard/httpintercepter';
import {Request, XHRBackend, XHRConnection} from '@angular/http';

Add provider in providers section

providers: [
{provide: XHRBackend, useClass: ApiXHRBackend }
],

then in your service.ts http call must be like below example

return this._http.post("/api/customerservice/loginvalidation",data)
.map((response: Response) => {
return response;
});

Here /api will be replaced by your base URL http://localhost:8080

more details http://shabeen.in/webschool/how-to-set-angular-2-service-http-base-url/

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!