我遵循官方教程并为Apis提供服务,但Api的绝对网址在服务中是硬编码的。
我想保留Api的基本网址,以便我可以在调用之前将其附加到每个服务的url路径中。我还需要在建造之前(或建筑之后)更改Api的基本网址。
我试图将它放在sessionstorage中,但这是一个坏主意,因为任何人都可以更改它,我的应用程序将开始进入其他域。
所以我保持硬编码并在git上放置一个后推钩以在构建后替换url。但它更像是黑客而不是解决方案。
我可以将文件放在angular的根目录中,并将Api url放在json格式中。并将其包含在每个服务中,以便我可以从git中排除文件,并且每个队友和构建服务器都可以拥有自己的文件,这些文件具有不同的URL。
建议的方法应该是什么?
答案 0 :(得分:20)
在Angular 4.3发布后,我们有可能使用HttpClient拦截器。 这种方法的优点是避免导入/注入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'
};
答案 1 :(得分:3)
使用环境文件
如果您使用cli,则应使用环境文件。通过配置angular-cli.json文件,您可以管理所有可用环境并创建新环境。例如,您可以创建一个environment.dev.js文件并将值存储在那里,方法是让git忽略它,团队中的任何成员都可以自定义。
表示环境文件将覆盖原始环境.js
请参阅此SO回答angular-cli for angular2 how to load environment variables
答案 2 :(得分:2)
通常我把它们放在const环境文件中。如果您使用的是angular-cli,那么已经为您提供了这个,如果没有,您可以创建自己的:
export const environment = {
production: false,
api: 'http://localhost:4200/api/'
};
您可以拥有多个环境文件,例如environment.production.ts,然后使用angular-cli运行:
ng build --environment=production
如果您不使用angular-cli,请确保您可以构建类似的东西。
答案 3 :(得分:1)
存储角度配置的位置
因为这是一个经常出现的问题,因为它经常做得不正确,并且还有很多其他选择,所以今天我想讨论在哪里存储Angular配置。您知道吗,当您从本地开发环境转移到开发,质量检查和生产服务器时,所有这些信息都会改变吗?
有一个地方!
错误的地方 我知道这很诱人,但是除了告诉运行时您正在运行代码的生产版本而不是在本地开发代码外,environment.ts和environment.prod.ts文件从来没有提供配置信息。是的,我知道可以为您的不同环境创建文件,并且您可以有效地使用该文件作为配置信息。但是,仅仅因为您可以,并不意味着您应该这样做。
在理想情况下,您将构建候选发布版本并将其放置在开发服务器上,然后从那里移至质量检查,再移至生产环境。您将永远不会重建应用程序。您要绝对确保在开发环境中测试的代码是您在QA环境中运行的代码,并且您在QA环境中运行的代码是在生产环境中运行的代码。您想确定唯一无法正常工作的原因是配置信息不正确。
还有其他减轻风险的方法,但是它们都涉及重新编译代码并标记存储库,以便您可以获取相同的代码。如果没有更好的方法,此方法将起作用。但是,有更好的方法!
在何处? 如果我们无法将配置信息放入代码中,该放在哪里?显然在您的代码外部。这给我们留下了几种解决方案。一种是创建一个静态json文件,当将代码部署到每个环境时,该文件将被复制到dist目录中。我看到的另一个工作是将代码放置在数据库中。数据库方法的优点在于,您可以拥有一个数据库来处理所有应用程序甚至所有环境的配置信息。在其上面放一个良好的管理GUI,您可以轻松更改配置,而无需部署文件。
跳跃障碍 现在,您已将配置信息放置在外部位置,您意识到需要进行GET请求才能检索该信息。您还可能很快意识到,应用程序启动后就需要该配置信息。毕竟把这些信息放在一个外部文件中不是一个好主意吗?
嗯,不是那么快!
Angular中有一个鲜为人知的API功能,它使我们可以预先加载内容,并且实际上将等到加载完成后再继续执行我们的代码。
APP_INITIALIZER APP_INITIALIZER是一种多提供程序类型,可让您指定一个返回承诺的工厂。承诺完成后,申请将继续进行。因此,当您到达代码中需要配置信息的位置时,可以确保已加载该信息。很漂亮。
import { APP_INITIALIZER } from '@angular/core'
@NgModule({
....
providers: [
...
{
provide: APP_INITIALIZER,
useFactory: load,
multi: true
}
]
)
其中load是一个函数,该函数返回一个返回Promise的函数。 promise函数将加载您的配置信息并将其存储在您的应用程序中。加载配置后,您可以使用resolve(true)解决承诺。
最后一点很重要。如果您弄错了,代码将不会等待加载完成再继续操作。 useFactory指向一个函数,该函数返回一个返回Promise的函数!
multi:真实的事情是因为APP_INITIALIZER允许此提供程序的多个实例。它们都同时运行,但是直到所有Promise都解决后,代码才能继续执行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 { }
答案 4 :(得分:0)
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 :(得分:-1)
在app module
添加窗口对象
import {provide} from 'angular2/core';
bootstrap([provide(Window, {useValue: window})]);
之后,您可以访问控制器中的window
constructor(private window: Window) {
var hostname = this.window.location.hostname;
}
没有角度2特定解决方案。在angularJS(版本1)中,我们使用$location
服务
$location.protocol() + "://" + $location.host() + ":" + $location.port();
答案 6 :(得分:-1)
您可以创建一个拦截器以添加基本API URL
adforest_load_search_countries();
/* Only need on this page so inluded here don't want to increase page size for optimizaion by adding extra scripts in all the web */
$mapType = adforest_mapType();
if( $mapType == 'leafletjs_map' )
{
}
else if( $mapType == 'google_map' )
{
wp_enqueue_script( 'google-map-callback');
}
wp_enqueue_script( 'adforest-search');
wp_enqueue_style( 'datepicker', trailingslashit( get_template_directory_uri () ) . 'css/datepicker.min.css' );
/*For Near By Ads */
$allow_near_by = (isset( $_GET['org'] ) && $_GET['org'] ) ? true : false;
$lat_lng_meta_query = array();
if( $allow_near_by )
{
$latlng = array();
if( $mapType == 'leafletjs_map' )
{
$map_lat = (isset($_GET['lat']) && $_GET['lat']) ? $_GET['lat'] : '';
$map_long = (isset($_GET['long']) && $_GET['long']) ? $_GET['long'] : '';
if( $map_lat != "" && $map_long != "" )
{
$latlng = array("latitude" => $map_lat, "longitude" => $map_long );
}
}
else if( $mapType == 'google_map' )
{
$latlng = adforest_getLatLong($_GET['org']);
}
if( count( $latlng ) > 0 )
{
$latitude = (isset($latlng['latitude'])) ? $latlng['latitude'] : '';
$longitude = (isset($latlng['longitude'])) ? $latlng['longitude'] : '';
$distance = (isset($_GET['rd'])) ? $_GET['rd'] : '20';
$data_array = array("latitude" => $latitude, "longitude" => $longitude, "distance" => $distance );
if( $latitude != "" && $longitude != "" )
{
$type_lat = "'DECIMAL'";
$type_lon = "'DECIMAL'";
$lats_longs = adforest_determine_minMax_latLong($data_array, false);
if(isset($lats_longs) && count($lats_longs) > 0 )
{
$lat_lng_meta_query[] = array(
'key' => '_adforest_ad_map_lat',
'value' => array($lats_longs['lat']['min'], $lats_longs['lat']['max']),
'compare' => 'BETWEEN',
'type' => 'DECIMAL',
);
$lat_lng_meta_query[] = array(
'key' => '_adforest_ad_map_long',
'value' => array($lats_longs['long']['min'], $lats_longs['long']['max']),
'compare' => 'BETWEEN',
'type' => 'DECIMAL',
);
add_filter('get_meta_sql','adforest_cast_decimal_precision');
if ( ! function_exists( 'adforest_cast_decimal_precision' ) )
{
function adforest_cast_decimal_precision( $array )
{
$array['where'] = str_replace('DECIMAL','DECIMAL(10,3)',$array['where']);
return $array;
}
}
}
}
}
}
$meta = array(
'key' => 'post_id',
'value' => '0',
'compare' => '!=',
);
// only active ads
$is_active = array(
'key' => '_adforest_ad_status_',
'value' => 'active',
'compare' => '=',
);
$condition = '';
if( isset( $_GET['condition'] ) && $_GET['condition'] != "" )
{
$condition = array(
'key' => '_adforest_ad_condition',
'value' => $_GET['condition'],
'compare' => '=',
);
}
$ad_type = '';
if( isset( $_GET['ad_type'] ) && $_GET['ad_type'] != "" )
{
$ad_type = array(
'key' => '_adforest_ad_type',
'value' => $_GET['ad_type'],
'compare' => '=',
);
}
$warranty = '';
if( isset( $_GET['warranty'] ) && $_GET['warranty'] != "" )
{
$warranty = array(
'key' => '_adforest_ad_warranty',
'value' => $_GET['warranty'],
'compare' => '=',
);
}
$feature_or_simple = '';
if( isset( $_GET['ad'] ) && $_GET['ad'] != "" )
{
$feature_or_simple = array(
'key' => '_adforest_is_feature',
'value' => $_GET['ad'],
'compare' => '=',
);
}
$currency = '';
if( isset( $_GET['c'] ) && $_GET['c'] != "" )
{
$currency = array(
'key' => '_adforest_ad_currency',
'value' => $_GET['c'],
'compare' => '=',
);
}
$price = '';
if( isset( $_GET['min_price'] ) && $_GET['min_price'] != "" )
{
$price = array(
'key' => '_adforest_ad_price',
'value' => array( $_GET['min_price'], $_GET['max_price'] ),
'type' => 'numeric',
'compare' => 'BETWEEN',
);
}
$location = '';
if( isset( $_GET['location'] ) && $_GET['location'] != "" )
{
$location = array(
'key' => '_adforest_ad_location',
'value' => trim( $_GET['location'] ),
'compare' => 'LIKE',
);
}
//Location
$countries_location = '';
if( isset( $_GET['country_id'] ) && $_GET['country_id'] != "" )
{
$countries_location = array(
array(
'taxonomy' => 'ad_country',
'field' => 'term_id',
'terms' => $_GET['country_id'],
),
);
}
$order = 'desc';
$orderBy = 'date';
if( isset( $_GET['sort'] ) && $_GET['sort'] != "" )
{
$orde_arr = explode('-', $_GET['sort']);
$order = isset($orde_arr[1]) ? $orde_arr[1] : 'desc';
if(isset($orde_arr[0]) && $orde_arr[0] == 'price')
{
$orderBy = 'meta_value_num';
}
else
{
$orderBy = isset($orde_arr[0]) ? $orde_arr[0] : 'date';
}
}
$category = '';
if( isset( $_GET['cat_id'] ) && $_GET['cat_id'] != "" )
{
$category = array(
array(
'taxonomy' => 'ad_cats',
'field' => 'term_id',
'terms' => $_GET['cat_id'],
),
);
}
$title = '';
if( isset( $_GET['ad_title'] ) && $_GET['ad_title'] != "" )
{
$title = $_GET['ad_title'];
}
$custom_search = array();
if( isset( $_GET['custom'] ) )
{
foreach($_GET['custom'] as $key => $val)
{
if( is_array($val) )
{
$arr = array();
$metaKey = '_adforest_tpl_field_'.$key;
foreach ($val as $v)
{
$custom_search[] = array(
'key' => $metaKey,
'value' => $v,
'compare' => 'LIKE',
);
}
}
else
{
if(trim( $val ) == "0" ) { continue; }
$val = stripslashes_deep($val);
$metaKey = '_adforest_tpl_field_'.$key;
$custom_search[] = array(
'key' => $metaKey,
'value' => $val,
'compare' => 'LIKE',
);
}
}
}
if ( get_query_var( 'paged' ) ) {
$paged = get_query_var( 'paged' );
} else if ( get_query_var( 'page' ) ) {
// This will occur if on front page.
$paged = get_query_var( 'page' );
} else {
$paged = 1;
}
$args = array(
's' => $title,
'post_type' => 'ad_post',
'post_status' => 'publish',
'posts_per_page' => get_option( 'posts_per_page' ),
'tax_query' => array(
$category,
$countries_location,
),
'meta_key' => '_adforest_ad_price',
'meta_query' => array(
$is_active,
$condition,
$ad_type,
$warranty,
$feature_or_simple,
$price,
$currency,
$location,
$custom_search,
$lat_lng_meta_query,
),
'order'=> $order,
'orderby' => $orderBy,
'paged' => $paged,
);
$results = new WP_Query( $args );
$left_col = 'col-md-8 col-lg-8 col-sx-12';
if( isset( $adforest_theme['design_type'] ) && $adforest_theme['design_type'] == 'modern' )
{
$left_col = 'col-md-9 col-lg-9 col-sx-12';
}
$search_layout = 'sidebar';
if( isset( $adforest_theme['design_type'] ) && $adforest_theme['design_type'] == 'modern' && isset( $adforest_theme['search_design'] ) && $adforest_theme['search_design'] != '' )
{
$search_layout = $adforest_theme['search_design'];
}
$GLOBALS['widget_counter'] = 0;
require trailingslashit( get_template_directory () ) . 'template-parts/layouts/search/search-' . $search_layout . '.php';
?>
<div class="panel panel-default my_panel">
<div class="search-modal modal fade cats_model" id="cat_modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">✕</span><span class="sr-only">Close</span></button>
<h3 class="modal-title text-center" id="lineModalLabel">
<i class="icon-gears"></i>
<?php echo __( 'Select Any Category', 'adforest' ); ?>
</h3>
</div>
<div class="modal-body">
<!-- content goes here -->
<div class="search-block">
<div class="row">
</div>
<div class="row">
<div class="col-md-12 col-xs-12 col-sm-12 popular-search" id="cats_response">
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" id="ad-search-btn" class="btn btn-lg btn-block"><?php echo __('Submit', 'adforest' ); ?></button>
</div>
</div>
</div>
</div>
</div>
<div class="search-modal modal fade states_model" id="states_model" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">✕</span><span class="sr-only">Close</span></button>
<h3 class="modal-title text-center">
<i class="icon-gears"></i>
<?php echo esc_html__( 'Select Your Location', 'adforest' ); ?>
</h3>
</div>
<div class="modal-body">
<!-- content goes here -->
<div class="search-block">
<div class="row">
<div class="col-md-12 col-xs-12 col-sm-12 popular-search" id="countries_response"></div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" id="country-btn" class="btn btn-lg btn-block"> <?php echo esc_html__( 'Submit', 'adforest' ); ?> </button>
</div>
</div>
</div>
</div>
上面的代码应该做。