Adding headers via HttpInterceptor Angular 5 - angular5

I want to add headers to post request from Angular 5 web app.
I've created the following Injectable class, registered in my app module:
#Injectable()
export class headerInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// Clone the request to add the new header
const authReq = req.clone({
headers: new HttpHeaders({
'Content-Type': 'application/json; charset=utf-8',
})
});
return next.handle(authReq);
}
}
I have network communication service and Im adding body parameters as below.
#Injectable()
export class NetworkService {
Root:string = 'some valid url';
results:Object[];
loading:boolean;
// inject Http client to our client service.
constructor(private httpClient: HttpClient ) {
}
login(loginParams : URLSearchParams){
let baseURL = `${this.Root}/login`;
this.httpClient.post(baseURL, JSON.stringify({'UserName':'123','Password':'123'} ))
.subscribe(data => {
console.log();
},
err => {
console.log('Error: ' + err.error);
});
when I put breakpoint after the clone method inside headerInterceptor class I can see the request body.
the problem is when I switch to network tab in chrome, I get 405 error and I can't see the body and the new headers. when I return the original request 'req'
the body sent ok but no new headers of course.

App Module,
import { HttpClientModule, HTTP_INTERCEPTORS } from '#angular/common/http';
import { headerInterceptor } from './httpinterceptor'
Add it to providers,
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: headerInterceptor,
multi: true
}
],
Now change the intereptor to, I have changed the way headers are added
#Injectable()
export class headerInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const authReq = req.clone({
headers:req.headers.set("Content-Type", "application/json; charset=utf-8")
});
return next.handle(authReq);
}
}
}
You can also use setHeaders:
#Injectable()
export class headerInterceptor implements HttpInterceptor {
constructor() {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {y
req = req.clone({
setHeaders: {
"Content-Type": "application/json; charset=utf-8"
}
});
return next.handle(req);
}
}

My problem was on server side I'm using ASP.net and wcf.
it seems that the server must implement CORS support when working with Angular 5 project (works ok with jQuery and cross domain tag).
this post helped me to add support in CORS:
http://blogs.microsoft.co.il/idof/2011/07/02/cross-origin-resource-sharing-cors-and-wcf/

Related

Angular Login issue

I am new in Angular 7. I am working in a Angular 7 project. I have a login component like below
import { Component, OnInit } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { TokenService } from '../../token.service'
import { Router, ActivatedRoute } from '#angular/router';
import { ServerService } from 'src/app/server.service';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
response: any;
failmsg: boolean = false;
constructor(private http: HttpClient,
private server: ServerService,
private Token: TokenService,
private router: Router,
private _router: ActivatedRoute
) { }
public form = {
grant_type: 'password',
client_id: 2,
client_secret: 'W5nQYuW1OFknDwiDnU96Y7dBMqTJ5jG6r6AXYk9q',
username: null,
password: null
}
headers = new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + this.handleResponse2()
});
login() {
this.http.post(this.server.base_url + "login", this.form).subscribe( //execution is not entering inside this block
(data) => {
this.handleResponse(data);
this.http.get(this.server.base_url + "employees/employee/user/profile", { headers: this.headers }).subscribe(
(profile) => {
this.employeeProfile = profile;
if (this.employeeProfile.user_id == 1) {
this.router.navigate([this._router.snapshot.paramMap.get("portal") + '/home/dashboard'])
.then(rel => location.reload());
} else {
localStorage.setItem('employeeId', this.employeeProfile.employeeId);
localStorage.setItem('id', this.employeeProfile.id);
this.router.navigate([this._router.snapshot.paramMap.get("portal") + '/home/employee-dashboard'])
.then(rel => location.reload());
}
}
)
},
(error) => { //execution is entering inside this block
console.log('hello');
if (error) {
this.failmsg = true;
}
console.log(error);
}
);
}
employeeProfile: any;
handleResponse(data) {
this.Token.set(data.access_token);
this.headers = new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + this.handleResponse2()
});
}
onClose() {}
handleResponse2() {
return this.Token.get();
}
ngOnInit() {
localStorage.setItem('portal', this._router.snapshot.paramMap.get("portal"));
this.server.set_base_url(this._router.snapshot.paramMap.get("portal"));
this.server.set_base_url2(this._router.snapshot.paramMap.get("portal"));
}
}
I can't login. I am getting error like below
My network tab is like below
Could anyone help me to fix this issue ?
Your target in proxy.conf should be http://alasr.com not localhost:4200.
What happen is --proxy-config option will treat http://alasr.com as though it is running on the same port as ur angular which is localhost:4200. So there will be no Cross Origin problem.
Btw, u can use npm 'start' script to give the proxy.conf file to the --proxy-config option
You are not able to hit the backend endpoints because of CORS- Cross origin resource sharing issue. You can check this link for more info: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
To fix this issue in angular you need to use --proxy-config option with your ng serve command. First, you need to create a JSON file proxy.conf.json and add below content:
{
"/al-asr": {
"target": "http://alasr.com",
"secure": false
}
}
I am assuming, Your backend is running in url http://alasr.com and url base is /al-asr.
Also in your httpClient pass the url like this
this.http.get('/al-asar/api/in/v1/employees/employee/user/profile')
Now run the server with below command to fix this issue:
ng serve --proxy-config proxy.conf.json
Try this
{
"/api": {
"target": "https://9c8c4aa0.ngrok.io",
"secure": true,
"changeOrigin": true,
"logLevel": "debug"
}
}

Angular 6 Http client custom url and header

I am working in an Angular 6 application and I was wondering what should be the best practice when customizing the url while sending requests to the server.
Here is the scenario:
- In my Angular project I have the environment.ts and environment.prod.ts where I added a "host" which contains the url:port of the http server (project with the controllers).
- I am creating Services to be injected in my components which will be responsible for sending requests (GETs and POSTs) to the server to retrieve data or to send updates.
- I want to use the "host" from the environment.ts as part of the request url. So ALL my requests will have the "host" as the base url and then i can concatenate to the desired path.
I already checked a few solutions and I already implemented one of them, but I am not sure this is the right practice. I will write below what i implemented so far and then i will write some ideas, please help me understand what is the best solution (I am new at angular)
Currently implemented:
-> In my feature services, like LoginService, I inject the angular HttpClient. Then I simply call:
return this.httpService.post("/login/", creds).pipe(
map((data: any) => {
this.manager = data;
return this.manager;
}));
I created an interceptor to make changes to the url: InterceptService implements HttpInterceptor where I create a new instance of the HttpRequest and customize the request.url using environment.host. I also needed the interceptor to add a Header for the authentication (still not fully implemented)
const httpRequest = new HttpRequest(<any>request.method, environment.host + request.url, request.body);
request = Object.assign(request, httpRequest);
const headers = new HttpHeaders({
'Authorization': 'Bearer token 123',
'Content-Type': 'application/json'
});
Questions:
1) This works, all my requests are changed in the interceptor as I
wanted, but it doesn't look like the best practice in my first look. I
don't like to create a new HeepRequest to be able to do this (i did it
to keep it immutable, I guess that's the correct way). Do you think
this looks good?
2) What about the Authentication being added to the Header in the interceptor? Is it ok? Most of the references I checked did this
Other solutions:
1) I saw some examples where a HttpClientService extends Http and each of the methods such as get and post edit the url and headers before calling super methods. But I believe this is not Angular 6 and is probably not preferrable
2) I could also create a service that receives an angular HttpClient (angular 6 HttpClientModule) instance by injection and I could implement the methods like get or post.
Well, as I didn't get any answers I will add my solution. i believe it's the best solution based on my researches.
I used an interceptor for adding information to the header such as the
token bearer authentication.
import { Injectable } from '#angular/core';
import {
HttpEvent,
HttpInterceptor,
HttpHandler,
HttpRequest,
HttpResponse,
HttpHeaders,
HttpErrorResponse
} from '#angular/common/http'
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
import { environment } from "../../../environments/environment";
import { Router } from "#angular/router";
export class HttpClientInterceptor implements HttpInterceptor {
constructor(private router: Router) { }
// intercept request to add information to the headers such as the token
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
//I decided to remove this logic from the interceptor to add the host url on the HttpClientService I created
//const httpRequest = new HttpRequest(<any>request.method, environment.host + request.url, request.body);
//request = Object.assign(request, httpRequest);
var token = localStorage.getItem("bearerToken");
if (token) {
const newReq = request.clone(
{
headers: request.headers.set('Authorization',
'Bearer ' + token)
});
return next.handle(newReq).pipe(
tap(event => {
if (event instanceof HttpResponse) {
console.log("Interceptor - HttpResponse = " + event.status); // http response status code
}
}, error => {
// http response status code
if (error instanceof HttpErrorResponse) {
console.log("----response----");
console.error("status code:");
console.error(error.status);
console.error(error.message);
console.log("--- end of response---");
if (error.status === 401 || error.status === 403) //check if the token expired and redirect to login
this.router.navigate(['login']);
}
})
)
}
else {
return next.handle(request);
}
};
For changing the url, I created a service on file
http-client.service.ts and got the host url from environment.ts
import { Injectable } from "#angular/core";
import { HttpClient } from '#angular/common/http';
import { Observable } from "rxjs";
import { environment } from "../../../environments/environment";
#Injectable({ providedIn:'root' })
export class HttpClientService {
constructor(private http: HttpClient) { }
get(url: string, options?: any): Observable<ArrayBuffer> {
url = this.updateUrl(url);
return this.http.get(url, options);
}
post(url: string, body: string, options?: any): Observable<ArrayBuffer> {
url = this.updateUrl(url);
return this.http.post(url, body, options);
}
put(url: string, body: string, options?: any): Observable<ArrayBuffer> {
url = this.updateUrl(url);
return this.http.put(url, body, options);
}
delete(url: string, options?: any): Observable<ArrayBuffer> {
url = this.updateUrl(url);
return this.http.delete(url,options);
}
private updateUrl(req: string) {
return environment.host + req;
}
}
As i said, I believe this is the best approach, but feel free to add information to my question/answer.

Unable to send data in headers to authorize the request in php

I am getting the error message in cli like :
Type 'Headers' has no properties in common with type 'RequestOptionsArgs'
. However, the code executes. The version I am using is 5, as it shows in package.json. I am unable to find a good http example, which suit my need. I want to send some parameters in headers section, and authorize it in php. Here is the service code:
user.service.ts
import { Observable } from 'rxjs/Observable';
import { Customer } from './../models/customer';
import { Injectable } from "#angular/core";
import { Http, Response, Headers, RequestOptions } from "#angular/http";
import "rxjs/add/operator/map";
import { apiServicesURL,appServicesURL } from "../constants/globals";
import { HttpClient, HttpHeaders } from "#angular/common/http";
#Injectable()
export class UserService {
//headers : Headers ;
constructor(private http: Http) {
}
getCustomerInfoo(custId): Observable<Customer> {
//cust.push({token : localStorage.getItem('token')});
console.log(apiServicesURL + 'getCustomers');
let token = localStorage.getItem('token');
let api_token = localStorage.getItem('api_token');
let email = localStorage.getItem('email');
let headers = new Headers({ 'Content-Type': 'application/json' });
// let options: RequestOptions = new RequestOptions({ headers: headers });
return this.http.post(apiServicesURL + 'getCustomers', JSON.stringify({ customer_id: custId, token: api_token, email: email }), headers ).map((response: Response) => {
// login successful if there's a jwt token in the response
return <Customer>response.json();
});
}
}
Any help, appreciated!!!
If you are using angular 5 then try it this below code and write RequestOptionsProvider to module.ts file
import { Injectable } from '#angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HTTP_INTERCEPTORS } from '#angular/common/http';
import { AuthService } from '#app/core/services/auth.service';
import { Observable } from 'rxjs/Observable';
#Injectable()
export class DefaultRequestOptionsService implements HttpInterceptor {
constructor(private auth: AuthService) { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// Get the auth header from the service.
// const authHeader = this.auth.getAuthorizationHeader();
// Clone the request to add the new header.
// const authReq = req.clone({headers: req.headers.set('Authorization', authHeader)});
const authReq = req.clone({ headers: req.headers.set('Content-Type', 'application/json') });
// Pass on the cloned request instead of the original request.
return next.handle(authReq);
}
}
export const RequestOptionsProvider = { provide: HTTP_INTERCEPTORS, useClass: DefaultRequestOptionsService, multi: true };

Nelmio_cors : error 400 when doing a POST to API

here is my problem. I have a front website on Angular 5 and a back API on Symfony 3.4.
I am using FOSRestBundle to make my API requests. When I try to do a POST request to my API, I got an error : "Failed to load http://127.0.0.1:8000/api/pro/login: Response for preflight has invalid HTTP status code 400."
Here are my different codes :
LoginController.php :
<?php
namespace ProBundle\Controller;
use FOS\RestBundle\Controller\Annotations as Rest;
use Proxies\__CG__\ProBundle\Entity\Utilisateur;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Response;
class LoginController extends Controller
{
/**
* #Rest\Post(
* path = "/api/pro/login",
* name = "dropnride_pro_login"
* )
* #Rest\View
* #ParamConverter("utilisateur", converter="fos_rest.request_body")
*/
public function loginAction(Utilisateur $utilisateur)
{
$response = new Response($utilisateur->loginToString());
return $response;
}
}
login.component.ts :
import { Component } from '#angular/core';
import { NgForm } from '#angular/forms';
import { LoginService } from '../services/login.service';
#Component({
selector: 'dropnride-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss'],
providers: [LoginService]
})
export class LoginComponent {
constructor(private _loginService: LoginService) { }
onSubmit(form: NgForm) {
const email = form.value['email'];
const password = form.value['password'];
this.askLogin(email, password);
}
askLogin(email: string, motDePasse: string) {
const userData = {
email: '',
motDePasse: '',
}
userData.email = email;
userData.motDePasse = motDePasse;
// Contact de l'API
this._loginService.getLoginData(userData);
}
}
login.service.ts :
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '#angular/common/http';
import { Observable } from 'rxjs/Observable';
const loginUrl = "http://127.0.0.1:8000/api/pro/login";
#Injectable()
export class LoginService {
constructor(private http: HttpClient) {
}
getLoginData(userData) {
const headers = new HttpHeaders({
'Content-Type': 'application/json'
});
console.log(userData);
return this.http.post(loginUrl, userData, {headers: headers}).subscribe(data => {
console.log(data);
});
}
}
My API calls works well with Postman :
API call through Postman
I have installed and configured NelmioCorsBundle in my config.yml :
nelmio_cors:
defaults:
allow_credentials: false
allow_origin: ['*']
allow_headers: ['*']
allow_methods: []
expose_headers: []
max_age: 0
hosts: []
origin_regex: false
forced_allow_origin_value: ~
paths:
'^/api/':
allow_origin: ['*']
allow_headers: ['X-Custom-Auth']
allow_methods: ['POST', 'PUT', 'GET', 'DELETE']
max_age: 3600
'^/':
origin_regex: true
allow_origin: ['^http://localhost:[0-9]+']
allow_headers: ['X-Custom-Auth']
allow_methods: ['POST', 'PUT', 'GET', 'DELETE']
max_age: 3600
hosts: ['^api\.']
I've nearly tried all of the other stackoverflow's members proposal for similar problems, I couldn't find a solution working for me... Would you have any idea that would help me with my problem ? Thanks a lot in advance :)
Try setting Content-Type too as allowed header
allow_headers: ['X-Custom-Auth', 'Content-Type]
And allow 'OPTIONS' (not sure if it's actually needed)
allow_methods: ['POST', 'PUT', 'GET', 'DELETE', 'OPTIONS']

Angular2 auth token in header request CORS/Preflight issue

I'm trying to request a HTTP GET call to my local REST REST http://demosite.com/mage_auth/api/rest it needs an authorization token to let a user call an endpoint.
So in my request I passed headers.set('Authorization', token) and content-type JSON, however it doesn't seems to be passing the header in the Request's Header when I check the network response.
I've created a httpClient Service to pass the auth token: --
createAuthorizationHeader(headers: Headers) {
var sample3Results = (new OAuthSimple()).sign({
path: 'http://www.demosites.com/mage_auth/',
signatures: {
'consumer_key': key,
'shared_secret': secret,
'access_token': token,
'access_secret': tokensecret
}
});
try {
console.debug('Sample 3', sample3Results);
} catch (e) { };
let headerAuth = sample3Results.header;
headers.set('Authorization', headerAuth);
headers.set('Content-Type', 'application/json; charset=UTF-8' );
}
get(url) {
let headers = new Headers();
this.createAuthorizationHeader(headers);
return this.http.get(url, {
headers: headers
});
}
My component request look like this: --
this.httClient.get('http://www.demosites.com/mage_auth/api/rest/products')
.map(res => res.json())
.subscribe(data => {
console.log('data: ', data);
})
The REST API is running on WAMP server, so I've also added some CORS values in httpd.conf
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Headers "origin, content-type"
Header set Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"
</IfModule>
And I'm still getting this Error.
XMLHttpRequest cannot load http://www.demosites.com/mage_auth/api/rest/products. Response for preflight has invalid HTTP status code 400
Just in case, I also added a proxy.config.json from Angular-cli as thought that'd fix it because the request is coming from localhost:4200. But seems wasn't the case, I'm out of idea why it still giving a preflight error.
Can someone point out what's wrong with this request?
That can be a misconfiguration of the CORS filter server side.
As for me, even if my CORS filter was well configured server side, I still faced the same issue. I used the RequestOptions of Angular for the headers. This is how I soved it within my angular service
Angular 2
header.append("Content-Type", "application/json");
header.append("X-Auth-Token", token);
let options = new RequestOptions({headers: header})
return this.http.get(url, options)
.toPromise()
.then(response => response.json())
.catch(this.handleError);
Angular 4.3
Define an interceptor
import {Injectable} from '#angular/core';
import {HttpRequest, HttpHandler, HttpEvent, HttpInterceptor} from '#angular/common/http';
import {Observable} from 'rxjs/Observable';
import {AppService} from '../app.service';
#Injectable()
export class Interceptor implements HttpInterceptor {
constructor() {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
request = request.clone({
setHeaders: {
token: `Bearer token`
}
});
return next.handle(request);
}
}
HttpRequests are immutable objects. So we need to copy them and then modidfy the copy.
Import the interceptor in app.module.ts
...
imports: [
BrowserModule,
HttpClientModule,
...
],
providers: [
{provide: HTTP_INTERCEPTORS, useClass: Interceptor, multi: true},
AppService
...
]
Use the interceptor in app.service.ts
import { Injectable } from '#angular/core';
import {Http, RequestOptions} from '#angular/http';
import 'rxjs/add/operator/map';
import {Observable} from 'rxjs/Observable';
import {HttpClient} from '#angular/common/http';
#Injectable()
export class AppService {
constructor(public http: HttpClient) { }
connectServer() {
return this.http.get('url')
.map(response => response);
}
}