So I have this interceptor class:
export class AddHeaderInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const headers = new HttpHeaders({
'app': getPackage().name,
'app-version': getPackage().version,
});
const cloneReq = req.clone({ headers });
req.clone({ headers: req.headers });
if (req.method !== 'GET' && !req.headers.has('Content-Type')) {
// Clone the request to add the new header
req = req.clone({
setHeaders: {
'Content-Type': 'application/json',
'app': getPackage().name,
'app-version': getPackage().version,
},
});
// Pass the cloned request instead of the original request to the next handle
return next.handle(req);
}
return next.handle(cloneReq);
}
}
It is meant to add those header properties to every request. Having to repeat the header properties twice is obviously bad code, but that's the only way I've been able to get it to work (For both GET and POST requests). Please how do I adjust it to call header properties once for both GET and POST requests?
Related
I have angular interceptor function. In this function I have request object.
intercept(req: HttpRequest<any>, next: HttpHandler) {
return next.handle(req);
}
What I want to do is to set my token in this request cookie with name my-token. How can I do that?
Of course I have access on token inside this function.
You just need to add Authorization header to your request:
intercept(req: HttpRequest < any >, next: HttpHandler) {
const authReq = req.clone({
headers: req.headers.set('Authorization', this.your_token)
});
return next.handle(authReq);
}
I have to put a token inside the 'Authorization' header for every HTTP request.
So I have developed and registered an HttpInterceptor :
#Injectable()
export class TokenInterceptor implements HttpInterceptor {
constructor(public authService: AuthService) {
}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
let modifiedReq;
const token = this.authService.getToken();
// we need the heck clone because the HttpRequest is immutable
// https://angular.io/guide/http#immutability
if (token) {
modifiedReq = request.clone();
modifiedReq.headers.set('Authorization', `Bearer ${token}`);
}
return next.handle(modifiedReq ? modifiedReq : request).pipe(tap(() => {
// do nothing
},
(err: any) => {
if (err instanceof HttpErrorResponse) {
if (err.status === 0) {
alert('what the heck, 0 HTTP code?');
}
if (err.status !== 401) {
return;
}
this.authService.goToLogin();
}
}));
}
}
But the header seems never to be put on the request sent. What am I doing wrong?
Also, sometimes an errorcode '0' gets caught by the interceptor; what does it mean?
Angular 8.2.11
EDIT 1: ------------------------
I've also tried like this:
request = request.clone({
setHeaders: {
authorization: `Bearer ${token}`
}
});
but still no header has been set.
Also, the module is correctly registered in app.module
providers: [{
provide: HTTP_INTERCEPTORS,
useClass: TokenInterceptor ,
multi: true,
}..
EDIT 2 : ------------------------
Check this image... I'm going crazy.
It's working for me like this:
const headersConfig = {
'Accept': 'application/json', //default headers
};
...
if (token) {
headersConfig['Authorization'] = `Bearer ${token}`;
}
...
return next
.handle(request.clone({
setHeaders: headersConfig
}))
maybe you forget to put in app.module this:
providers: [{
provide: HTTP_INTERCEPTORS,
useClass: TokenInterceptor ,
multi: true,
}..
the final part write in this way:
return next.handle(modifiedReq);
I was wrong. When doing update of the clone request, angular will put the new headers in fields called "lazyUpdate" and not direcly inside the headers.
The requests were failing because of other reasons.
I'm building the front-end of an application in Angular 8. This application uses an OAuth 2 implementation to manage authentication (password grant) so any HTTP request (with the exception of ones to the token endpoint) needs to have on its header a valid access_token.
To provide said token I've made an Angular interceptor that retrieve the token from another service and then attach it to the intercepted HTTP request. The token retrieval method doesn't give directly the token but an observable which eventually resolves to a valid token, I made this choice because the access token may not be instantly available, if the token is expired the application needs to refresh it with an HTTP call and then the refreshed token can be passed to the HTTP interceptor.
The problem which I encounter is that despite my many attempts the interceptor doesn't wait for the token to be retrieved so at the end the interceptor is skipped and the HTTP request is made without any token attached.
This is the code of my interceptor, retrieveValidToken is the Observable which returns the token.
import { Injectable } from '#angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '#angular/common/http';
import { FacadeService } from './facade.service';
import { Observable } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class HttpInterceptorService implements HttpInterceptor {
constructor(private facadeService: FacadeService) { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (req.url.includes('localhost:3000') && !req.url.endsWith('token')) {
this.facadeService.retrieveValidToken()
.subscribe(
(res) => {
const clone = req.clone({ setHeaders: { Authorization: `Bearer ${res}` } });
return next.handle(clone);
},
(err) => {
const clone = req.clone({ setHeaders: { Authorization: `Bearer ` } });
return next.handle(clone);
}
);
} else {
return next.handle(req);
}
}
}
Observables are asynchronous. The code outside the subscribe method will not wait for the code inside.
You should return observable by itself, not only result inside its subscription:
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (req.url.includes('localhost:3000') && !req.url.endsWith('token')) {
return this.facadeService.retrieveValidToken()
.subscribe(
res => {
const clone = req.clone({ setHeaders: { Authorization: `Bearer ${res}` } });
return next.handle(clone);
}
);
} else {
return next.handle(req);
}
}
Something similar:
How use async service into angular httpClient interceptor
The problem is that 'intercept' method should return observable immediately, so instead of subscribing to 'this.facadeService.retrieveValidToken()' use the following code:
return this.facadeService.retrieveValidToken().pipe(
mergeMap(token =>
next.handle(req.clone({ setHeaders: { Authorization: 'Bearer ${token}' }))
)
)
Hey i have implemented an api which is a GET request
now what i want is Response Header values but only some of them are showing in the api reponse but in network tab every value is showing
i dont know what is the problem
this is my Http service
pendingResultData(payload: Payload, headerConfig?: {}) {
const params = payload
? {
type: payload.type,
data_scopes: payload.data_scopes,
observe: 'response',
...headerConfig
}
: { observe: 'response', ...headerConfig };
const reqUrl = '/api/data_capture';
return this.timerService.timer(this.httpService.getFullResponse(reqUrl, params));
}
this is my interceptor
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
this.idToken = this.authService.getAccessToken() || '';
// cloning original request and set/add new headers
const authReq = req.clone({
headers: this.idToken
? req.headers
.set('Authorization', `Bearer ${this.idToken}`)
.set('Access-Control-Allow-Origin', '*')
.set('Content-Type', 'application/json')
.set("Access-Control-Expose-Headers", "*")
: req.headers,
params: req.params
});
return next.handle(authReq);
}
now the headers are coming in response header you can see in Screen shot
i want total, current-page, per-page but headers i am getting in api response are
headers: "content-length: 194
content-type: application/json; charset=utf-8
cache-control: max-age=0, private, must-revalidate"
i wanna know am i doing something wrong and if this a backend problem or not?
any help?
thanks
You can access these by user response.headers.get() method. e.g:
this.httpService.getFullResponse(reqUrl, params).subscribe(response=> {
console.log(response.headers.get('per-page'));
});
i think you have to add your custom headers to "access-control-expose-headers" in the backend response. In your screenshot from above it looks that their are not in the list.
(https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers)
https://github.com/angular/angular/issues/5237#issuecomment-441081290
I am using a restapi and it requires that I add a token to the header before I can create a new record.
Right now I have a service to create a new record which looks like this:
service.ts
create(title, text) {
let headers: HttpHeaders = new HttpHeaders();
headers = headers.append('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
headers = headers.append('Authorization', token); // Not added yet as this is the reason for the question
return this.http.post('http://myapi/api.php/posts', {
title: 'added title',
text: 'added text'
}, { headers });
}
app.component.ts
add() {
this.service.create('my title', 'body text').subscribe(result => {
console.log(result);
});
}
The problem with this is that it won't let me add the new record because it requires a token and in order to get a token I need to run this:
getToken() {
let headers: HttpHeaders = new HttpHeaders();
headers = headers.append('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
return this.http.post('http://myapi/api.php/user', {
username: 'admin',
password: 'password'
}, { headers });
}
My question is...How do I get this two together into one call instead of two...or when is the best way to do this?
Apart from what #Pardeep Jain already mentioned, you can add an interceptor (> Angular version 4, you mentioned you're using 5) for your HttpClient that will automatically add Authorization headers for all requests.
If you need top be authenticated for only one request, it's better to keep things simple and use Pardeep's solution.
If you want to be authenticated for most of your requests, then add an interceptor.
module, let's say app.module.ts
#NgModule({
//...
providers: [
//...
{
provide: HTTP_INTERCEPTORS,
useClass: JwtInterceptor,
multi: true
},
//...
]
//...
})
and your jwt interceptor, let's say jwt.interceptor.ts
#Injectable()
export class JwtInterceptor implements HttpInterceptor {
constructor(private injector: Injector, private router: Router) {
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const authReq = req.clone({
headers: req.headers.set('Authorization', /* here you fetch your jwt */this.getToken())
.append('Access-Control-Allow-Origin', '*')
});
return next.handle(authReq).do((event: HttpEvent<any>) => {
if (event instanceof HttpResponse) {
// do stuff with response if you want
}
}, (response: HttpErrorResponse) => { });
}
getToken() {
let headers: HttpHeaders = new HttpHeaders();
headers = headers.append('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
return this.http.post('http://myapi/api.php/user', {
username: 'admin',
password: 'password'
}, { headers });
}
}
If you want to read something, more here: https://medium.com/#ryanchenkie_40935/angular-authentication-using-the-http-client-and-http-interceptors-2f9d1540eb8
My question is...How do I get this two together into one call instead
of two...or when is the best way to do this?
You should not.
Authentication is one thing that should be performed a single time for the client or as the authentication ticket has expired.
Posting some content is another thing that you should not mix with authentication.
So authenticate the client once and store the ticket.
Then pass the ticket in the header for any request to a secured endpoints/methods. Or use a transverse way as an interceptor to set it in the send requests if you don't want to repeat the code.
The code should be like this -
create(title, text) {
let headers: HttpHeaders = new HttpHeaders();
headers.append('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
headers.append('Authorization', token);
return this.http.post('http://myapi/api.php/posts', {
title: 'added title',
text: 'added text'
}, { headers });
}