Подтвердить что ты не робот

Как сохранить корневой URL-адрес api в приложении angular 4?

Я следил за официальными учебниками и делал услуги для Apis, но абсолютный URL-адрес Api жестко закодирован в сервисах.

Я хочу сохранить базовый url Api где-нибудь, чтобы я мог добавить его к URL-адресу в каждой службе перед вызовом. Мне также нужно изменить базовый url Api перед зданием (или после здания).

Я попытался поместить его в sessionstorage, но это плохая идея, так как любой может изменить его, и мое приложение начнет удалять другой домен.

поэтому я сохранил его жестко запрограммированным и разместил куклу post-push на git, чтобы заменить url после сборки. но это больше похоже на хак, чем на решение.

Могу ли я поместить файл в корневой каталог angular и поместить URL-адрес Api в json-формат. И включите его в каждую службу, чтобы я мог исключить файл из git, и каждый товарищ по команде и сервер сборки могут иметь свой собственный файл с другим URL-адресом.

Каким должен быть рекомендуемый способ сделать это?

4b9b3361

Ответ 1

Использовать файлы окружения

Если вы используете cli, вы должны использовать файлы окружения. Конфигурируя файл angular -cli.json, вы можете управлять всеми доступными средами и создавать новые. Например, вы можете создать файл environment.dev.js и сохранить там значения, сделав git игнорировать его, любой член вашей команды может иметь индивидуальный вариант.

Указанный файл окружения перезапишет исходную среду .js

Смотрите этот ответ SOA angular -cli для angular2 как загрузить переменные среды

Ответ 2

После выпуска Angular 4.3 у нас есть возможность использовать HttpClient interceprtors. Преимуществом этого метода является исключение импорта/впрыскивания API_URL - это все службы с вызовами api.

Это моя основная реализация:

@Injectable()
export class ApiUrlInterceptor implements HttpInterceptor {
constructor(@Inject(API_URL) private apiUrl: string) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    req = req.clone({url: this.prepareUrl(req.url)});
    return next.handle(req);
  }

  private isAbsoluteUrl(url: string): boolean {
    const absolutePattern = /^https?:\/\//i;
    return absolutePattern.test(url);
  }

  private prepareUrl(url: string): string {
    url = this.isAbsoluteUrl(url) ? url : this.apiUrl + '/' + url;
    return url.replace(/([^:]\/)\/+/g, '$1');
  }
}

Объявление InjectionToken:

export const API_URL = new InjectionToken<string>('apiUrl');

Регистрация провайдера:

{provide: API_URL, useValue: environment.apiUrl}
{provide: HTTP_INTERCEPTORS, useClass: ApiUrlInterceptor, multi: true, deps: [API_URL]}

Environment.ts:

export const environment = {
 production: false,
 apiUrl: 'some-dev-api'
};

Ответ 3

Обычно я помещаю их в файл окружения const. Если вы используете angular -cli, это уже предусмотрено для вас, если вы не можете создать свой собственный:

export const environment = {  
  production: false,
  api: 'http://localhost:4200/api/'
};

У вас может быть несколько файлов окружения, таких как environment.production.ts, а затем angular -cli:

ng build --environment=production

Если вы не используете angular -cli, достаточно уверены, что можете создать свое собственное нечто подобное.

Ответ 4

export class AppSettings {
   public static API_ENDPOINT='http://127.0.0.1:6666/api/';
}

И затем в сервисе:

import {Http} from 'angular2/http';
import {Message} from '../models/message';
import {Injectable} from 'angular2/core';
import {Observable} from 'rxjs/Observable';
import {AppSettings} from '../appSettings';
import 'rxjs/add/operator/map';

@Injectable()
export class MessageService {

    constructor(private http: Http) { }

    getMessages(): Observable<Message[]> {
        return this.http.get(AppSettings.API_ENDPOINT+'/messages')
            .map(response => response.json())
            .map((messages: Object[]) => {
                return messages.map(message => this.parseData(message));
            });
    }

    private parseData(data): Message {
        return new Message(data);
    }
}

Ответ 5

В app module добавить объект окна

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

После этого вы можете получить доступ к window в контроллере

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

Нет специального решения angular 2. В angularJS (версия 1) мы используем $location service

$location.protocol() + "://" + $location.host() + ":" + $location.port();

Ответ 6

Вы можете создать Interceptor для добавления базового URL API

@Injectable()
export class CustomHttpInterceptor implements HttpInterceptor {

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    console.log('Custom Interceptor');

    // Adding serverHostURL to all APIs in Interceptor
    const serverHostURL = 'http://localhost:8080';
    request = request.clone({
      url: serverHostURL + request.url
    });


    return next.handle(request);
  }

Выше код должен делать.

Ответ 7

Где хранить угловые конфигурации от Dave Notebook Где хранить угловые конфигурации

Поскольку это частая проблема, потому что это часто делается неправильно и потому что есть отличная альтернатива, сегодня я хочу обсудить, где хранить угловые конфигурации. Вы знаете, всю эту информацию, которая меняется при переходе из локальной среды разработки на серверы разработки, контроля качества и производства?

Есть место для этого!

Неправильное место Я знаю, что это заманчиво, но файлы environment.ts и environment.prod.ts никогда не предназначались для информации о конфигурации, кроме как для того, чтобы сообщить во время выполнения, что вы работаете с рабочей версией кода, а не разрабатываете код локально. Да, я знаю, что можно создать файл для ваших различных сред, и вы можете эффективно использовать файл для своей информации о конфигурации. Но то, что вы можете, не означает, что вы должны это делать.

В идеальном мире вы должны создать кандидата на выпуск и разместить его на своем сервере разработки, а затем переместить его оттуда в QA, а затем в производство. Вы бы никогда не перестроили приложение. Вы хотите быть абсолютно уверены, что код, который вы тестировали в среде разработки, - это код, который вы запускали в среде QA, и что код, который вы запускали в среде QA, - это код, который выполняется в рабочей среде. Вы хотите точно знать, что единственная возможная причина, по которой что-то не работает, заключается в том, что информация о конфигурации неверна.

Существуют и другие способы снижения риска, но все они включают перекомпиляцию кода и маркировку вашего хранилища, чтобы вы могли получить тот же код обратно. Это работает, когда нет лучшего способа. Но есть лучший способ!

Где вместо? Если мы не можем поместить нашу конфигурационную информацию в наш код, куда мы ее поместим? Очевидно внешний по отношению к вашему коду. Это оставляет нам несколько решений. Одним из них является создание статического файла JSON, который копируется в каталог dist при развертывании кода в каждой среде. Другое место, где я вижу работу, - это поместить код в базу данных. Преимущество метода базы данных в том, что у вас может быть одна база данных, которая обрабатывает информацию о конфигурации для всех ваших приложений и даже для всех ваших сред. Положите на него хороший графический интерфейс администратора, и вы сможете легко изменить конфигурацию, не развертывая даже файл.

Прыжки через препятствие Теперь, когда вы поместили информацию о своей конфигурации во внешнее местоположение, вы понимаете, что вам нужно будет выполнить запрос GET для получения этой информации. Вы также можете быстро понять, что вам нужна эта информация о конфигурации, как только ваше приложение запустится. Может быть, поместить эту информацию во внешний файл не было такой хорошей идеей в конце концов?

Ну, не так быстро!

В Angular есть немного известная функция API, которая позволяет нам загружать файлы заранее и фактически будет ждать завершения загрузки, прежде чем продолжить работу с нашим кодом.

APP_INITIALIZER APP_INITIALIZER - это тип с несколькими поставщиками, который позволяет вам указать фабрику, которая возвращает обещание. Когда обещание будет выполнено, заявка продолжится. Поэтому, когда вы добираетесь до места в вашем коде, где вам нужна информация о конфигурации, вы можете быть уверены, что она была загружена. Это довольно гладко.

import { APP_INITIALIZER } from '@angular/core'

@NgModule({
    ....
    providers: [
        ...
        {
            provide: APP_INITIALIZER,
            useFactory: load,
            multi: true
        }
    ]
)

где load - это функция, которая возвращает функцию, которая возвращает Promise. Функция обещания загружает информацию о вашей конфигурации и сохраняет ее в вашем приложении. После того, как ваша конфигурация была загружена, вы разрешаете обещание, используя resol (true).

Этот последний пункт действительно важен. Если вы ошиблись, код не будет ждать окончания загрузки, прежде чем двигаться дальше. useFactory указывает на функцию, которая возвращает функцию, которая возвращает Promise!

Multi: true, потому что APP_INITIALIZER допускает несколько экземпляров этого провайдера. Все они работают одновременно, но код не будет продолжаться после APP_INTITIALIZER, пока все Обещания не будут решены.

Пример. Теперь, в качестве темы для обсуждения, давайте предположим, что у вас есть обычный проект на основе Angular CLI, и вам нужно загрузить базовое местоположение ваших конечных точек REST. У вас может быть файл config.json, который выглядит примерно так:

{
    "baseUrl": "https://davembush.github.io/api"
}

Вы должны создать разные из них для каждой среды, в которой вы хотите развернуть, и, как часть вашего процесса развертывания, вы скопируете соответствующий файл в config.json в том же месте, в котором вы развернули весь свой Angular CLI. сгенерированные статические файлы.

Базовый инициализатор приложения Теперь мы хотим загрузить этот файл конфигурации во время выполнения, используя APP_INITIALIZER. Для этого добавим провайдера APP_INITIALIZER в наш файл app.module.ts.

import { APP_INITIALIZER } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';

function load() {

}

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [{
    provide: APP_INITIALIZER,
    useFactory: load,
    multi: true
  }],
  bootstrap: [AppComponent]
})
export class AppModule { }

Полный результирующий код На всякий случай, если я пропустил шаг, или вы потерялись, или, возможно, все, что вас действительно волнует, это код, чтобы вы могли скопировать и вставить его.

import { APP_INITIALIZER } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule, HttpClient } from '@angular/common/http';

import { AppComponent } from './app.component';
import { ConfigService } from './config.service';
import { of, Observable, ObservableInput } from '../../node_modules/rxjs';
import { map, catchError } from 'rxjs/operators';

function load(http: HttpClient, config: ConfigService): (() => Promise<boolean>) {
  return (): Promise<boolean> => {
    return new Promise<boolean>((resolve: (a: boolean) => void): void => {
       http.get('./config.json')
         .pipe(
           map((x: ConfigService) => {
             config.baseUrl = x.baseUrl;
             resolve(true);
           }),
           catchError((x: { status: number }, caught: Observable<void>): ObservableInput<{}> => {
             if (x.status !== 404) {
               resolve(false);
             }
             config.baseUrl = 'http://localhost:8080/api';
             resolve(true);
             return of({});
           })
         ).subscribe();
    });
  };
}
@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule
  ],
  providers: [{
      provide: APP_INITIALIZER,
      useFactory: load,
      deps: [
        HttpClient,
        ConfigService
      ],
      multi: true
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }