import {Headers} from 'angular2/http';
var headers = new Headers();
headers.append(headerName, value);
// HTTP POST using these headers
this.http.post(url, data, {
headers: headers
})
// do something with the response
参考文献
,但是以这种方式为每个请求手动设置请求标头是不可行的。
用户登录后如何设置标头集,并在注销时删除标头?
#1 楼
要回答这个问题,您是否可以提供包装来自Angular的原始Http
对象的服务。如下所述。import {Injectable} from '@angular/core';
import {Http, Headers} from '@angular/http';
@Injectable()
export class HttpClient {
constructor(private http: Http) {}
createAuthorizationHeader(headers: Headers) {
headers.append('Authorization', 'Basic ' +
btoa('username:password'));
}
get(url) {
let headers = new Headers();
this.createAuthorizationHeader(headers);
return this.http.get(url, {
headers: headers
});
}
post(url, data) {
let headers = new Headers();
this.createAuthorizationHeader(headers);
return this.http.post(url, data, {
headers: headers
});
}
}
而不是注入
Http
对象,您可以注入这个对象(HttpClient
)。import { HttpClient } from './http-client';
export class MyComponent {
// Notice we inject "our" HttpClient here, naming it Http so it's easier
constructor(http: HttpClient) {
this.http = httpClient;
}
handleSomething() {
this.http.post(url, data).subscribe(result => {
// console.log( result );
});
}
}
我还认为通过为
Http
类提供自己的类来扩展Http
的类,可以使用针对q4312079q类的多个提供程序来完成某些工作...请参阅此链接:http://blog.thoughtram.io/angular2/2015/ 11/23 / multi-providers-in-angular-2.html。评论
“ this.http = http;”在哪里?来自,我相信我们需要在使用之前声明它?
– co2f2e
16-10-7在2:04
角度标题(设置和附加函数)正在“标准化”标题的键并将其变为小写。来自Headers.d.ts://“ HTTP字符集由不区分大小写的标记标识” //规范,网址为tools.ietf.org/html/rfc2616。这是一个绕过的方法:let headersMap = .get(options,'headers._headersMap',new Map()); headersMap.set('Authorization',[.replace(Bearer $ {token},/ \“ / g,'')]));
– sangress
16-10-18在19:22
@DiegoUnanue我正在使用Angular 2的最终版本和Thierry的实现工作。只需在导入语句中将“ angular2”替换为“ @angular”即可。
– f123
16-10-28在3:57
Mark Pieszak-我应该包括HttpClient的提供程序吗?
–user3127109
16-12-21在11:16
现在TS抛出错误:`类型参数'{headers:Headers; }”不能分配给“ RequestOptionsArgs”类型的参数
– elporfirio
17年6月6日在15:34
#2 楼
现在可以从HttpClient
的新@angular/common/http
(从Angular 4.3.x版本开始)使用HTTP拦截器。现在为每个请求添加标头非常简单:
import {
HttpEvent,
HttpInterceptor,
HttpHandler,
HttpRequest,
} from '@angular/common/http';
import { Observable } from 'rxjs';
export class AddHeaderInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// Clone the request to add the new header
const clonedRequest = req.clone({ headers: req.headers.append('Authorization', 'Bearer 123') });
// Pass the cloned request instead of the original request to the next handle
return next.handle(clonedRequest);
}
}
有一个原理不变性的原因,这就是在请求上设置新内容之前必须先克隆请求的原因。
由于编辑标头是一项非常常见的任务,实际上(在克隆请求时)有一个快捷方式:
const clonedRequest = req.clone({ setHeaders: { Authorization: 'Bearer 123' } });
创建拦截器后,应使用
HTTP_INTERCEPTORS
提供的功能对其进行注册。import { HTTP_INTERCEPTORS } from '@angular/common/http';
@NgModule({
providers: [{
provide: HTTP_INTERCEPTORS,
useClass: AddHeaderInterceptor,
multi: true,
}],
})
export class AppModule {}
评论
我实现了这个功能,当执行ng服务时我可以看到请求标头,但是当执行ng b prod并在tomcat中进行部署时,我没有看到标头...使用spring-boot,标头去了哪里?
–naoru
17年8月15日在1:56
不知道是否是因为我正在使用Express节点API,但即使使用正式的Angular文档,它也不适用于我。 :/
–马克西姆·拉法里(Maxime Lafarie)
17年8月25日在7:42
错误TypeError:在非对象上调用CreateListFromArrayLike
– DAG
17年8月25日在23:07
您如何将任何东西注入HttpInterceptor?
– Zaitsman
17-10-19在23:38
我已经实现了相同的功能,但是在PUT和DELETE API中,请求标头对我不起作用。
–Pooja
18年2月12日在11:19
#3 楼
在这种情况下,扩展BaseRequestOptions
可能会很有帮助。签出以下代码:import {provide} from 'angular2/core';
import {bootstrap} from 'angular2/platform/browser';
import {HTTP_PROVIDERS, Headers, Http, BaseRequestOptions} from 'angular2/http';
import {AppCmp} from './components/app/app';
class MyRequestOptions extends BaseRequestOptions {
constructor () {
super();
this.headers.append('My-Custom-Header','MyCustomHeaderValue');
}
}
bootstrap(AppCmp, [
ROUTER_PROVIDERS,
HTTP_PROVIDERS,
provide(RequestOptions, { useClass: MyRequestOptions })
]);
每个呼叫中都应包含“ My-Custom-Header”。
更新:
要能够随时更改标题而不是上面的代码,您还可以使用以下代码添加新的标题:
this.http._defaultOptions.headers.append('Authorization', 'token');
删除您可以执行
this.http._defaultOptions.headers.delete('Authorization');
还可以使用另一个函数来设置值:
this.http._defaultOptions.headers.set('Authorization', 'token');
以上解决方案在Typescript上下文中仍然不是完全有效。 _defaultHeaders受保护,不应该这样使用。我建议使用上述解决方案进行快速修复,但从长远来看,最好围绕http调用编写自己的包装器,该包装器还可以处理auth。请从auth0中获取以下示例,它更好,更干净。
https://github.com/auth0/angular2-jwt/blob/master/angular2-jwt.ts
更新-2018年6月
我看到很多人都在寻求这种解决方案,但我建议不要这样做。全局追加标头会将身份验证令牌发送到从您的应用发出的每个api调用。因此,前往第三方插件(例如内部通信或zendesk或任何其他API)的api调用也将带有您的授权标头。这可能会导致很大的安全漏洞。
因此,相反,请全局使用拦截器,但要手动检查传出的呼叫是否朝向服务器的api端点,然后附加身份验证标头。
评论
this.http._defaultOptions.headers.delete('My-Custom-Header')因此,可以通过以下代码this.http._defaultOptions.headers.append('My-New-Custom-Header','newvalue ')
– anit
16 Jan 28'在3:29
@Dinistro是的,现在我不建议自己这样做。由于角度beta的限制以及我在全局控制身份验证流的习惯,我不得不提出这种解决方法。但是我相信现在github.com/auth0/angular2-jwt/blob/master/angular2-jwt.ts有更好更好的解决方案。
– anit
16 Mar 21 '16 at 12:16
使用BaseRequestOptions的问题是它的构造函数在浏览器的应用程序生存期内仅运行一次。因此,如果您想在一段时间内更改标头值(例如csrf_token),则无法采用这种方式(即使在此类中重写merge方法也无济于事:()
–卡米尔(KamilKiełczewski)
16年7月7日在8:40
问题是,如果您使用包装器来直接访问HTTP的第三方库,则需要重新编写才能使用它。我仍然不知道该如何解决。确实需要拦截器。不知道是否有人知道更好的方法。
–Piotr Stulinski
16年8月12日在16:09
嗨,在angular4中,_defaultOptions受保护,因此无法从服务中调用
– Andurit
17 Mar 29 '17 at 12:02
#4 楼
尽管我回答得很晚,但可能会对其他人有所帮助。要在使用@NgModule
时将标头注入所有请求,可以执行以下操作:(我在Angular 2.0.1中进行了测试)
/**
* Extending BaseRequestOptions to inject common headers to all requests.
*/
class CustomRequestOptions extends BaseRequestOptions {
constructor() {
super();
this.headers.append('Authorization', 'my-token');
this.headers.append('foo', 'bar');
}
}
现在在
@NgModule
中执行以下操作:@NgModule({
declarations: [FooComponent],
imports : [
// Angular modules
BrowserModule,
HttpModule, // This is required
/* other modules */
],
providers : [
{provide: LocationStrategy, useClass: HashLocationStrategy},
// This is the main part. We are telling Angular to provide an instance of
// CustomRequestOptions whenever someone injects RequestOptions
{provide: RequestOptions, useClass: CustomRequestOptions}
],
bootstrap : [AppComponent]
})
评论
您需要@Injectable并在类中定义标头,我通过@Injectable()导出类成功测试了成功。CustomRequestOptions扩展了BaseRequestOptions {headers:Headers = new Headers({'Authorization':'xxx'}); }
–EasonBlack
16-10-12在7:49
好吧,我在2.0.0中做到了,没有检查2.0.1
–EasonBlack
16-10-12在7:53
重要说明在这里,我遇到了一个问题,即使使用@ Inject / @ Injectable,也无法将任何东西注入到CustomRequestOptions中。我意识到的解决方案是扩展RequestOptions,而不是BaseRequestOptions。提供BaseRequestOptions无效,但是扩展RequestOptions会使DI重新工作。
–议会
16年11月9日在14:07
此解决方案很简单,但是如果用户将注销并重新登录并且其令牌更改-将不再起作用,因为Authorization标头仅在应用程序初始化时设置一次。
– Alex Paramonov
16年11月10日在10:09
是的,正确@AlexeyVParamonov。仅当令牌设置一次时,此功能才有用。否则,我们将像您所说的那样编写拦截器。
– Shashank Agrawal
16年11月10日在16:17
#5 楼
在Angular 2.1.2
中,我通过扩展有角度的Http来解决这个问题: import {Injectable} from "@angular/core";
import {Http, Headers, RequestOptionsArgs, Request, Response, ConnectionBackend, RequestOptions} from "@angular/http";
import {Observable} from 'rxjs/Observable';
@Injectable()
export class HttpClient extends Http {
constructor(protected _backend: ConnectionBackend, protected _defaultOptions: RequestOptions) {
super(_backend, _defaultOptions);
}
_setCustomHeaders(options?: RequestOptionsArgs):RequestOptionsArgs{
if(!options) {
options = new RequestOptions({});
}
if(localStorage.getItem("id_token")) {
if (!options.headers) {
options.headers = new Headers();
}
options.headers.set("Authorization", localStorage.getItem("id_token"))
}
return options;
}
request(url: string|Request, options?: RequestOptionsArgs): Observable<Response> {
options = this._setCustomHeaders(options);
return super.request(url, options)
}
}
现在我不需要声明每个Http方法,并且可以在整个应用程序中正常使用
http
。评论
由于我能够将网址过滤到我的api服务器,并且仅将Auth令牌添加到对其进行的调用中,因此该答案对我来说效果最好。我将请求更改为:request(url:string | Request,options ?: RequestOptionsArgs):Observable
–克里斯·霍尔科姆(Chris Holcomb)
16-12-31在11:40
在我的情况下,withCredentials和Headers是从request方法的url参数中获取的。我更改了这样的代码:request(url:string | Request,options ?: RequestOptionsArgs):Observable
–Argnist
17 Mar 14 '17 2:33
您正在重载的request()方法具有两个调用签名,并且options属性仅在将url指定为字符串时使用。如果url是Request的实例,则options属性将被忽略。这可能导致难以捕获的错误。请参阅我的答案以获取更多详细信息。
– Slava Fomin II
17年6月14日在18:36
请注意,此解决方案在服务器平台方面存在一些问题。但是有一些解决方法可以避免这种情况。
– Alireza Mirian
17年8月30日在21:13
这对我一直有效,直到有角度4.2。 4.3具有拦截器。
–cabaji99
17-10-6在23:49
#6 楼
通过扩展Angular 2Http
提供程序来创建自定义Http类,并在自定义Http类中简单地重写constructor
和request
方法。下面的示例在每个http请求中添加Authorization
标头。import {Injectable} from '@angular/core';
import {Http, XHRBackend, RequestOptions, Request, RequestOptionsArgs, Response, Headers} from '@angular/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
@Injectable()
export class HttpService extends Http {
constructor (backend: XHRBackend, options: RequestOptions) {
let token = localStorage.getItem('auth_token'); // your custom token getter function here
options.headers.set('Authorization', `Bearer ${token}`);
super(backend, options);
}
request(url: string|Request, options?: RequestOptionsArgs): Observable<Response> {
let token = localStorage.getItem('auth_token');
if (typeof url === 'string') { // meaning we have to add the token to the options, not in url
if (!options) {
// let's make option object
options = {headers: new Headers()};
}
options.headers.set('Authorization', `Bearer ${token}`);
} else {
// we have to add the token to the url object
url.headers.set('Authorization', `Bearer ${token}`);
}
return super.request(url, options).catch(this.catchAuthError(this));
}
private catchAuthError (self: HttpService) {
// we have to pass HttpService's own instance here as `self`
return (res: Response) => {
console.log(res);
if (res.status === 401 || res.status === 403) {
// if not authenticated
console.log(res);
}
return Observable.throw(res);
};
}
}
,然后配置主
app.module.ts
,以将XHRBackend
提供为ConnectionBackend
提供程序,并将RequestOptions
提供给自定义Http类: import { HttpModule, RequestOptions, XHRBackend } from '@angular/http';
import { HttpService } from './services/http.service';
...
@NgModule({
imports: [..],
providers: [
{
provide: HttpService,
useFactory: (backend: XHRBackend, options: RequestOptions) => {
return new HttpService(backend, options);
},
deps: [XHRBackend, RequestOptions]
}
],
bootstrap: [ AppComponent ]
})
之后,您现在可以在服务中使用自定义的http提供程序。例如:
import { Injectable } from '@angular/core';
import {HttpService} from './http.service';
@Injectable()
class UserService {
constructor (private http: HttpService) {}
// token will added automatically to get request header
getUser (id: number) {
return this.http.get(`/users/${id}`).map((res) => {
return res.json();
} );
}
}
这里是综合指南-http://adonespitogo.com/articles/angular-2-extending-http-provider/
评论
这种方法非常适合使用替代类提供程序。您可以使用“ provide:Http”代替通常在模块中使用的“ provide:HttpService”,而可以使用模块中的“ provide:HttpService”。
–吉尔伯特·阿里纳斯匕首
16年11月22日在22:05
如何向此扩展的http类添加其他属性?例如,路由器:路由器或任何自定义可注入服务。
–shafeequemat
17-09-23在2:59
@shafeequemat您不能使用此功能。您可以在自定义http类中定义另一个方法,例如setRouter(router)。或者,您可以创建另一个类,然后在其中注入自定义的http类,而不是相反。
– Adones Pitogo
18年3月20日在12:06
#7 楼
对于Angular 5及更高版本,我们可以使用HttpInterceptor来概括请求和响应操作。这有助于我们避免重复:
1)通用标头
2)指定响应类型
3)查询请求
import { Injectable } from '@angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor,
HttpResponse,
HttpErrorResponse
} from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/do';
@Injectable()
export class AuthHttpInterceptor implements HttpInterceptor {
requestCounter: number = 0;
constructor() {
}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
request = request.clone({
responseType: 'json',
setHeaders: {
Authorization: `Bearer token_value`,
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
}
});
return next.handle(request).do((event: HttpEvent<any>) => {
if (event instanceof HttpResponse) {
// do stuff with response if you want
}
}, (err: any) => {
if (err instanceof HttpErrorResponse) {
// do stuff with response error if you want
}
});
}
}
我们可以使用AuthHttpInterceptor类作为HttpInterceptor的提供程序:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app.routing-module';
import { AuthHttpInterceptor } from './services/auth-http.interceptor';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule,
BrowserAnimationsModule,
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: AuthHttpInterceptor,
multi: true
}
],
exports: [],
bootstrap: [AppComponent]
})
export class AppModule {
}
#8 楼
迟来总比没有好... =)您可以采用扩展
BaseRequestOptions
的概念(从这里https://angular.io/docs/ts/latest/guide/server-communication.html# !#override-default-request-options)并“即时”刷新标头(不仅在构造函数中)。您可以像这样使用getter / setter“ headers”属性替代:import { Injectable } from '@angular/core';
import { BaseRequestOptions, RequestOptions, Headers } from '@angular/http';
@Injectable()
export class DefaultRequestOptions extends BaseRequestOptions {
private superHeaders: Headers;
get headers() {
// Set the default 'Content-Type' header
this.superHeaders.set('Content-Type', 'application/json');
const token = localStorage.getItem('authToken');
if(token) {
this.superHeaders.set('Authorization', `Bearer ${token}`);
} else {
this.superHeaders.delete('Authorization');
}
return this.superHeaders;
}
set headers(headers: Headers) {
this.superHeaders = headers;
}
constructor() {
super();
}
}
export const requestOptionsProvider = { provide: RequestOptions, useClass: DefaultRequestOptions };
评论
稍作更新:为获得更好的性能,您可以考虑将所有静态标头(如“ Content-Type”)移至构造函数
–АлександрИльинский
17年5月15日在13:25
#9 楼
这就是我为每个请求设置令牌的方式。import { RequestOptions, BaseRequestOptions, RequestOptionsArgs } from '@angular/http';
export class CustomRequestOptions extends BaseRequestOptions {
constructor() {
super();
this.headers.set('Content-Type', 'application/json');
}
merge(options?: RequestOptionsArgs): RequestOptions {
const token = localStorage.getItem('token');
const newOptions = super.merge(options);
if (token) {
newOptions.headers.set('Authorization', `Bearer ${token}`);
}
return newOptions;
}
}
并在app.module.ts中注册
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule
],
providers: [
{ provide: RequestOptions, useClass: CustomRequestOptions }
],
bootstrap: [AppComponent]
})
export class AppModule { }
#10 楼
这是已接受答案的改进版本,已针对Angular2 final更新:import {Injectable} from "@angular/core";
import {Http, Headers, Response, Request, BaseRequestOptions, RequestMethod} from "@angular/http";
import {I18nService} from "../lang-picker/i18n.service";
import {Observable} from "rxjs";
@Injectable()
export class HttpClient {
constructor(private http: Http, private i18n: I18nService ) {}
get(url:string):Observable<Response> {
return this.request(url, RequestMethod.Get);
}
post(url:string, body:any) {
return this.request(url, RequestMethod.Post, body);
}
private request(url:string, method:RequestMethod, body?:any):Observable<Response>{
let headers = new Headers();
this.createAcceptLanguageHeader(headers);
let options = new BaseRequestOptions();
options.headers = headers;
options.url = url;
options.method = method;
options.body = body;
options.withCredentials = true;
let request = new Request(options);
return this.http.request(request);
}
// set the accept-language header using the value from i18n service that holds the language currently selected by the user
private createAcceptLanguageHeader(headers:Headers) {
headers.append('Accept-Language', this.i18n.getCurrentLang());
}
}
当然,如果需要,应将其扩展为
delete
和put
之类的方法(我不愿意我的项目现在还不需要它们。)优点是
get
/ post
/ ...方法中的重复代码更少。请注意,就我而言,我使用Cookie进行身份验证。我需要i18n的标头(
Accept-Language
标头),因为我们的API返回的许多值都是用用户的语言翻译的。在我的应用程序中,i18n服务保留用户当前选择的语言。评论
您是如何让tslint忽略标头的?
– Winnemucca
17 Mar 13 '17 at 6:55
#11 楼
如何保持如下所示的单独服务 import {Injectable} from '@angular/core';
import {Headers, Http, RequestOptions} from '@angular/http';
@Injectable()
export class HttpClientService extends RequestOptions {
constructor(private requestOptionArgs:RequestOptions) {
super();
}
addHeader(headerName: string, headerValue: string ){
(this.requestOptionArgs.headers as Headers).set(headerName, headerValue);
}
}
,当您从另一个地方调用此服务时,请使用
this.httpClientService.addHeader("Authorization", "Bearer " + this.tok);
,您会看到添加的标题例如:-如下授权
#12 楼
经过一番调查,我发现最终最简单的方法就是扩展我喜欢的BaseRequestOptions
。以下是出于某些原因我尝试放弃的方法:
1。扩展
BaseRequestOptions
并在constructor()
中添加动态标头。如果我登录,它将无法正常工作。它将创建一次。因此它不是动态的。2。扩展
Http
。与上述相同的原因,我无法在constructor()
中添加动态标头。如果我重写request(..)
方法并设置标题,例如:request(url: string|Request, options?: RequestOptionsArgs): Observable<Response> {
let token = localStorage.getItem(AppConstants.tokenName);
if (typeof url === 'string') { // meaning we have to add the token to the options, not in url
if (!options) {
options = new RequestOptions({});
}
options.headers.set('Authorization', 'token_value');
} else {
url.headers.set('Authorization', 'token_value');
}
return super.request(url, options).catch(this.catchAuthError(this));
}
您只需要覆盖此方法,但不必覆盖每个get / post / put方法。
3.我的首选解决方案是扩展
BaseRequestOptions
并覆盖merge()
:@Injectable()
export class AuthRequestOptions extends BaseRequestOptions {
merge(options?: RequestOptionsArgs): RequestOptions {
var newOptions = super.merge(options);
let token = localStorage.getItem(AppConstants.tokenName);
newOptions.headers.set(AppConstants.authHeaderName, token);
return newOptions;
}
}
此
merge()
函数将为每个请求调用。/>
评论
在给出的所有答案中,这是引起我注意的答案,因为我已经寻求了基于扩展BaseRequestOptions的解决方案。但是,可悲的是,这对我没有用。任何可能的原因?
–航行
17年5月13日在12:54
使它工作。这个解决方案很好,我的服务器有问题。我必须对CORS飞行前请求进行一些配置。请参阅此链接stackoverflow.com/a/43962690/3892439
–航行
17年5月15日在3:51
您如何将AuthRequestOptions绑定到应用程序的其余部分?我尝试将其放在提供程序部分中,但没有执行任何操作。
–特拉维斯公园
17年6月19日在18:55
您必须覆盖RequestOptions的提供程序,而不是BaseRequestOptions。 angular.io/api/http/BaseRequestOptions
–特拉维斯公园
17年6月19日在19:03
在我的应用程序中,我只扩展了BaseRequestOptions,它已经扩展了RequestOptions。然后在app.module中,应设置提供者:{提供:RequestOptions,useClass:AuthRequestOptions}
–马夫拉恩
17年6月20日在7:00
#13 楼
尽管我回答得很晚,但是如果有人正在寻求更简单的解决方案。我们可以使用angular2-jwt。从Angular 2应用发出HTTP请求时,angular2-jwt可自动将JSON Web令牌(JWT)附加为授权标头。
我们可以使用高级配置选项设置全局标头
export function authHttpServiceFactory(http: Http, options: RequestOptions) {
return new AuthHttp(new AuthConfig({
tokenName: 'token',
tokenGetter: (() => sessionStorage.getItem('token')),
globalHeaders: [{'Content-Type':'application/json'}],
}), http, options);
}
并按请求发送令牌,如
getThing() {
let myHeader = new Headers();
myHeader.append('Content-Type', 'application/json');
this.authHttp.get('http://example.com/api/thing', { headers: myHeader })
.subscribe(
data => this.thing = data,
err => console.log(error),
() => console.log('Request Complete')
);
// Pass it after the body in a POST request
this.authHttp.post('http://example.com/api/thing', 'post body', { headers: myHeader })
.subscribe(
data => this.thing = data,
err => console.log(error),
() => console.log('Request Complete')
);
}
评论
有助于转到github.com/auth0/angular2-jwt#installation并使用其安装指南来调整此答案
–祖里尔
17年6月18日在20:40
#14 楼
我喜欢覆盖默认选项的想法,这似乎是一个不错的解决方案。但是,如果您打算扩展Http
类。请务必通读!这里的一些答案实际上表明
request()
方法的不正确重载,这可能导致难以捕捉的错误和奇怪的行为。我自己偶然发现了这个问题。此解决方案基于Angular
request()
中的4.2.x
方法实现,但应与将来兼容: import {Observable} from 'rxjs/Observable';
import {Injectable} from '@angular/core';
import {
ConnectionBackend, Headers,
Http as NgHttp,
Request,
RequestOptions,
RequestOptionsArgs,
Response,
XHRBackend
} from '@angular/http';
import {AuthenticationStateService} from '../authentication/authentication-state.service';
@Injectable()
export class Http extends NgHttp {
constructor (
backend: ConnectionBackend,
defaultOptions: RequestOptions,
private authenticationStateService: AuthenticationStateService
) {
super(backend, defaultOptions);
}
request (url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
if ('string' === typeof url) {
url = this.rewriteUrl(url);
options = (options || new RequestOptions());
options.headers = this.updateHeaders(options.headers);
return super.request(url, options);
} else if (url instanceof Request) {
const request = url;
request.url = this.rewriteUrl(request.url);
request.headers = this.updateHeaders(request.headers);
return super.request(request);
} else {
throw new Error('First argument must be a url string or Request instance');
}
}
private rewriteUrl (url: string) {
return environment.backendBaseUrl + url;
}
private updateHeaders (headers?: Headers) {
headers = headers || new Headers();
// Authenticating the request.
if (this.authenticationStateService.isAuthenticated() && !headers.has('Authorization')) {
headers.append('Authorization', 'Bearer ' + this.authenticationStateService.getToken());
}
return headers;
}
}
请注意,我正以这种方式导入原始类
import { Http as NgHttp } from '@angular/http';
以防止名称冲突。此处解决的问题是
request()
方法具有两个不同的调用签名。当传递Request
对象而不是URL string
时,Angular会忽略options
参数。因此,这两种情况都必须得到正确处理。这是如何使用DI容器注册此重写的类的示例:
export const httpProvider = {
provide: NgHttp,
useFactory: httpFactory,
deps: [XHRBackend, RequestOptions, AuthenticationStateService]
};
export function httpFactory (
xhrBackend: XHRBackend,
requestOptions: RequestOptions,
authenticationStateService: AuthenticationStateService
): Http {
return new Http(
xhrBackend,
requestOptions,
authenticationStateService
);
}
通过这种方法,您可以正常地注入
Http
类,但是您被覆盖的类将被神奇地注入。这使您可以轻松集成解决方案,而无需更改应用程序的其他部分(实际上是多态)。只需将
httpProvider
添加到模块元数据的providers
属性即可。#15 楼
最简单的创建
config.ts
文件import { HttpHeaders } from '@angular/common/http';
export class Config {
url: string = 'http://localhost:3000';
httpOptions: any = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': JSON.parse(localStorage.getItem('currentUser')).token
})
}
}
然后在您的
service
上,只需导入config.ts
文件import { Config } from '../config';
import { HttpClient } from '@angular/common/http';
@Injectable()
export class OrganizationService {
config = new Config;
constructor(
private http: HttpClient
) { }
addData(data): Observable<any> {
let sendAddLink = `${this.config.url}/api/addData`;
return this.http.post(sendAddLink , data, this.config.httpOptions).pipe(
tap(snap => {
return snap;
})
);
}
我认为这是最简单,最安全的。
#16 楼
角度2.0.1及更高版本有一些更改: import {RequestOptions, RequestMethod, Headers} from '@angular/http';
import { BrowserModule } from '@angular/platform-browser';
import { HttpModule } from '@angular/http';
import { AppRoutingModule } from './app.routing.module';
import { AppComponent } from './app.component';
//you can move this class to a better place
class GlobalHttpOptions extends RequestOptions {
constructor() {
super({
method: RequestMethod.Get,
headers: new Headers({
'MyHeader': 'MyHeaderValue',
})
});
}
}
@NgModule({
imports: [ BrowserModule, HttpModule, AppRoutingModule ],
declarations: [ AppComponent],
bootstrap: [ AppComponent ],
providers: [ { provide: RequestOptions, useClass: GlobalHttpOptions} ]
})
export class AppModule { }
评论
不起作用,我自己尝试过。除了刷新之外,不会调用其他任何东西。
–菲尔
17年5月9日下午5:04
#17 楼
我可以选择一个更简单的解决方案>通过您的api get(或其他)函数将新的Headers添加到默认选项中,以进行合并或加载。get(endpoint: string, params?: any, options?: RequestOptions) {
if (!options) {
options = new RequestOptions();
options.headers = new Headers( { "Accept": "application/json" } ); <<<<
}
// [...]
}
当然,您可以在默认选项中或类中的任何内容中将此标头外部化。
这是在Ionic生成的api.ts @Injectable()导出类API {}中
,它非常快速,对我有用。我不想要json / ld格式。
#18 楼
您可以使用一些授权标头创建自己的http客户端:import {Injectable} from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class HttpClientWithAuthorization {
constructor(private http: HttpClient) {}
createAuthorizationHeader(bearerToken: string): HttpHeaders {
const headerDict = {
Authorization: 'Bearer ' + bearerToken,
}
return new HttpHeaders(headerDict);
}
get<T>(url, bearerToken) {
this.createAuthorizationHeader(bearerToken);
return this.http.get<T>(url, {
headers: this.createAuthorizationHeader(bearerToken)
});
}
post<T>(url, bearerToken, data) {
this.createAuthorizationHeader(bearerToken);
return this.http.post<T>(url, data, {
headers: this.createAuthorizationHeader(bearerToken)
});
}
}
,然后将其替换为服务类中的
HttpClient
:@Injectable({
providedIn: 'root'
})
export class SomeService {
constructor(readonly httpClientWithAuthorization: HttpClientWithAuthorization) {}
getSomething(): Observable<Object> {
return this.httpClientWithAuthorization.get<Object>(url,'someBearer');
}
postSomething(data) {
return this.httpClientWithAuthorization.post<Object>(url,'someBearer', data);
}
}
#19 楼
您可以在路由中使用canActive
,例如:import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { CanActivate } from '@angular/router';
import { AuthService } from './auth.service';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private auth: AuthService, private router: Router) {}
canActivate() {
// If user is not logged in we'll send them to the homepage
if (!this.auth.loggedIn()) {
this.router.navigate(['']);
return false;
}
return true;
}
}
const appRoutes: Routes = [
{
path: '', redirectTo: '/deals', pathMatch: 'full'
},
{
path: 'special',
component: PrivateDealsComponent,
/* We'll use the canActivate API and pass in our AuthGuard.
Now any time the /special route is hit, the AuthGuard will run
first to make sure the user is logged in before activating and
loading this route. */
canActivate: [AuthGuard]
}
];
来自:https://auth0.com/blog/angular-2-authentication
评论
参见stackoverflow.com/questions/34502398/…angulartutorial.net/2017/11/…