14

I have metronic_v5.5.2 Angular Version and I am trying to integrate Its angular version with my backend API.

As I am pretty new to all this, Now the issue is with my proxy configuration that is not working according to my expectations.

The following is the code of proxyconfig.json file

{
    "/api": {
        "target": "https://localhost:5001",
        "secure": false,
        "changeOrigin": true,
        "logLevel": "debug"
    }
}

Image is showing that the request is routing to the URL "https://localhost:5001/api/auth/login" POST /api/auth/login -> https://localhost:5001

But In browsers' console this request is actually routing to the URL http://localhost:4200/api/auth/login which return 401 error. I am unable to route on clicking of button to the url: https://localhost:5001/api/auth/login

Following is the HTML Code

<!--begin::Form-->
<form class="m-login__form m-form" name="form" (ngSubmit)="f.form.valid && submit()" #f="ngForm" novalidate>
    <div class="form-group">
        <mat-form-field>
            <mat-label>Email</mat-label>
            <input matInput type="email" name="email" placeholder="Email address" autocomplete="off" [(ngModel)]="model.email" #email="ngModel" email="true" required>
        </mat-form-field>
    </div>
    <div class="form-group">
        <mat-form-field>
            <mat-label>Password</mat-label>
            <input matInput minlength="4" type="password" name="password" placeholder="Password" autocomplete="off" [(ngModel)]="model.password" #password="ngModel" required>
        </mat-form-field>
    </div>
</form>
<!--end::Form-->

<!--begin::Action-->
<div class="m-login__action m-login__action--fit">
    <a href="javascript:;" (click)="forgotPasswordPage($event)" class="m-link">
        <span translate="AUTH.GENERAL.FORGOT_BUTTON">Forgot Password?</span>
    </a>
    <m-spinner-button [options]="spinner" (click)="submit()">{{'AUTH.LOGIN.BUTTON' | translate}}</m-spinner-button>
</div>

Following is the login.component.ts code

submit() {
        this.spinner.active = true;
        if (this.validate(this.f)) {
            this.authServiceDb.logindb(this.model).subscribe(response => {
                    this.router.navigate(['/']);
                    this.alertify.success('Logged In Successfully');
                    this.spinner.active = false;
                    this.cdr.detectChanges();
            }, error => {
                this.alertify.error(error);
            });
        }
    }

function the code for authdb exported class is given blow, Edit

import { Injectable } from '@angular/core';
import { Http, Headers, RequestOptions, Response } from '../../../node_modules/@angular/http';
import { map, catchError } from 'rxjs/operators';
import { throwError } from '../../../node_modules/rxjs';
import { tokenNotExpired, JwtHelper } from 'angular2-jwt';

@Injectable({
    providedIn: 'root'
})
export class AuthdbService {
    baseUrl = 'api/auth/';
    userToken: any;
    decodedTokenn: any;
    jwtHelper: JwtHelper = new JwtHelper();
    constructor(private http: Http) { }
public logindb(model: any) {
    return this.http.post(this.baseUrl + 'login', model, this.requestOptions()).pipe(map((response: Response) => {
      const user = response.json();
      if (user) {
        localStorage.setItem('token', user.tokenString);
        this.decodedTokenn = this.jwtHelper.decodeToken(user.tokenString);
        this.userToken = user.tokenString;
      }
    })).pipe(catchError(this.handleError));
  }
  register(model: any) {
    return this.http.post(this.baseUrl + 'register', model, this.requestOptions()).pipe(catchError(this.handleError));
  }
  loggedIn() {
    return tokenNotExpired('token');
  }
  private requestOptions() {
    const headers = new Headers({
      'Content-type': 'application/json'});
    return new RequestOptions({headers: headers});
  }
  private handleError(error: any) {
    const applicationError = error.headers.get('Application-Error');
    if (applicationError) {
      return throwError(applicationError);
    }
    const serverError = error.json();
    let modelStateErrors = '';
    if (serverError) {
      for (const key in serverError) {
        if (serverError[key]) {
          modelStateErrors += serverError[key] + '\n';
        }
      }
    }
    return throwError(
      modelStateErrors || 'Server Eroor'
    );
  }
}

And In My package.json I have the following code

{
    "name": "default",
    "version": "0.0.0",
    "license": "MIT",
    "scripts": {
        "ng": "ng",
        "start": "ng serve --proxy-config proxyconfig.json",
        "build": "ng build --prod",
        "test": "ng test",
        "lint": "ng lint",
        "e2e": "ng e2e"
    },
    "private": true,
    "dependencies": {
        "@angular/animations": "^6.1.0",
        "@angular/cdk": "^6.4.0",
        "@angular/common": "^6.1.0",
        "@angular/compiler": "^6.1.0",
        "@angular/forms": "^6.1.0",
        "@angular/http": "^6.1.0",
        "@angular/platform-browser": "^6.1.0",
        "@angular/platform-browser-dynamic": "^6.1.0",
        "@angular/platform-server": "^6.1.0",
        "@angular/router": "^6.1.0",
        "@kolkov/angular-editor": "^0.10.3",
        "@ng-bootstrap/ng-bootstrap": "^2.2.0",
        "@ngx-loading-bar/core": "^2.1.1",
        "@ngx-translate/core": "^10.0.2",
        "@types/lodash": "^4.14.112",
        "alertifyjs": "^1.11.1",
        "angular-in-memory-web-api": "^0.6.0",
        "angular2-jwt": "^0.2.3",
        "chart.js": "^2.7.2",
        "classlist.js": "^1.1.20150312",
        "core-js": "^2.5.7",
        "hammerjs": "^2.0.8",
        "lodash": "^4.17.10",
        "material-design-icons": "^3.0.1",
        "ng2-charts": "^1.6.0",
        "ngx-auth": "4.0.0",
        "ngx-highlightjs": "^2.0.4",
        "ngx-perfect-scrollbar": "^6.2.0",
        "ngx-permissions": "^5.0.0",
        "object-path": "^0.11.4",
        "rxjs-compat": "^6.2.2",
        "rxjs-tslint": "^0.1.5",
        "web-animations-js": "^2.3.1",
        "zone.js": "^0.8.26"
    },
    "devDependencies": {
        "@angular-devkit/build-angular": "^0.7.0",
        "@angular/cli": "^6.0.8",
        "@angular/compiler-cli": "^6.1.0",
        "@angular/core": "^6.1.0",
        "@angular/language-service": "^6.1.0",
        "@angular/material": "^6.4.0",
        "@angular/material-moment-adapter": "^6.4.0",
        "@types/jasmine": "^2.8.8",
        "@types/jasminewd2": "^2.0.3",
        "@types/node": "^10.5.2",
        "codelyzer": "^4.4.2",
        "jasmine": "^3.1.0",
        "jasmine-core": "^3.1.0",
        "jasmine-spec-reporter": "~4.2.1",
        "karma": "~2.0.4",
        "karma-chrome-launcher": "^2.2.0",
        "karma-coverage-istanbul-reporter": "^2.0.1",
        "karma-jasmine": "^1.1.2",
        "karma-jasmine-html-reporter": "^1.2.0",
        "moment": "^2.22.2",
        "protractor": "^5.3.2",
        "rxjs": "^6.2.2",
        "ts-node": "^6.0.3",
        "tslint": "~5.9.1",
        "typescript": "2.7.2"
    }
}
Hafiz Siddiq
  • 671
  • 3
  • 9
  • 23
  • If you're using a proxy, the url in browser is still showing http://localhost:4200/ even if it's actually using the proxy. I think there is no error and you just got a true 401 error. 401 means unauthorized, are you sure to be authorized to access the resource? Don't you have to set an Authorization header? – Powkachu Aug 28 '18 at 12:41
  • Actually, the post request is going to the wrong URL, as I mentioned in the post. It is going to – Hafiz Siddiq Aug 28 '18 at 18:51
  • "But In browsers' console this request is actually routing to the URL http://localhost:4200/api/auth/login which return 401 error (and it is not the URL for Actual API to which I have Made the Call). I have tested the API with POSTMAN and API is working OK, It seems the Proxyconfigurations is not working because of some reasons I am unable to route on clicking of button to the url: https://localhost:5001/api/auth/login" – Hafiz Siddiq Aug 28 '18 at 18:52
  • I had an issue exactly same with the picture provided which is request to /api/auth/login is incorrectly routed to https://localhost:5001. It's fixed when I put "target": "https://localhost:5001/api" and "pathRewrite": { "^/api" : "" } in the config. Now it's correctly routed to https://localhost:5001/api/auth/login. – Mandakh Jan 25 '19 at 02:18

6 Answers6

10

I had this same issue and adding proxyConfig option to the serve target did the job.

Go to angular.json -> within serve add the key:value pair "proxyConfig": "proxy.conf.json"

like this -

"architect": {
  "serve": {
    "builder": "@angular-devkit/build-angular:dev-server",
    "options": {
      "browserTarget": "your-application-name:build",
      "proxyConfig": "proxy.conf.json"
    },

btw, I got this from here

confused human
  • 401
  • 8
  • 23
  • This worked for me with Angular v6. Proxy rewrite needed to send requests to a different (non-localhost) domain on my network and this seeing worked form my proxy.conf.js file. Thanks! – RoboBear Jan 03 '19 at 18:41
5

It took me a couple of hours to fix incorrect routing of POST /api/auth/login to https://localhost:5001 which is in the image you provided.

Following config fixes the routing of POST /api/auth/login to https://localhost:5001/api/auth/login.

{
    "/api": {
        "target": "https://localhost:5001/api",
        "changeOrigin": true,
        "logLevel": "debug",
        "pathRewrite": { "^/api" : "" }
    }
}
Mandakh
  • 1,073
  • 1
  • 9
  • 10
4

You said you are new to this, so let me explain something simple first.

When you call http.post the first parameter is the url that will be contacted. So:

this.http.post(this.baseUrl + 'login', ...

will become

this.http.post('api/auth/login', ...

because you set baseUrl and added 'login':

baseUrl = 'api/auth/';

But your code does not say which protocol to use (http or https) NOR which domain:port to call (eg. http://mydomain:port/api/auth/login).

Therefore Angular will default to 'http' and to the domain and port that IT is using, which is localhost:4200. So your request then becomes:

http://localhost:4200/api/auth/login

That is why you see that in the console. Angular is completely ignoring your proxy file. I think the reason is either the name, or location (it should normally be in your project's root folder) or you have not told Angular to load it.

You need to tell Angular to actually use it when it starts up. So in package.json you need something like this:

"start": "ng serve --proxy-config proxyconfig.json"

This tells Angular-CLI that when you use the npm run start (or just npm start) command to start the app, it should load the proxy data from that json file in the root folder.

I would advise reading this tutorial also.

Also, I think you have /* missing from your proxyconfig:

{
    "/api/*": {
        "target": "http://localhost:5001",
        "secure": false,
        "changeOrigin": true,
        "logLevel": "debug"
    }
}
rmcsharry
  • 5,363
  • 6
  • 65
  • 108
  • I have also this line in my package.json file, as you can see in the Edited post, I am unable to get my code working actually I am using Matronic UI, There may any problem in integration. Please Guide Me how to proceed. – Hafiz Siddiq Sep 03 '18 at 11:16
  • I updated my answer as I had a small mistake - for the proxy file to actually work you cannot use ng serve, you have to use npm start (which will the call the "start" command defined in your package.json). See this for more info: https://stackoverflow.com/questions/40190538/when-to-use-npm-start-and-when-to-use-ng-serve – rmcsharry Sep 03 '18 at 20:32
  • Dear there is the same result as I run the "npm start" and then click on the sign in button the request is going to wrong URL (Proxy Config file is not working). The same issue, I am facing here, after changin my proxycong.json file, Please help its too much frustrating for me now. – Hafiz Siddiq Sep 04 '18 at 08:37
  • @HafizSiddiq It seems you have everything setup correctly so I have no idea why the proxy file is not working. Sorry but there is nothing more I can do to help you. – rmcsharry Sep 04 '18 at 09:57
  • I am following all of this and still get 401. The backend has Windows Auth enabled. Is that the credentials that I need to provide somehow? – Mark Aug 23 '19 at 13:23
  • @Mark this is about frontend, not backend. A 401 means your frontend is not passing the correction authentication credentials - and if the backend uses Windows Auth then I am afraid I cannot help, as this solutions is about sending a JOSN Token, not Windows Auth credentials. – rmcsharry Aug 26 '19 at 10:46
0

Add "--ssl" parameter to ng serve:

"start": "ng serve --proxy-config proxyconfig.json --ssl",

because you want to build a secure connection:

"target": "https://localhost:5001",

source: https://www.devdungeon.com/content/how-serve-angular-locally-over-https

Balazs F.
  • 380
  • 5
  • 10
0

To configure proxy in Angular follow below steps -

Step 1. In angular root folder where package.json file exist create "proxy.conf.json" and add below code -

{
  "/api/*": {
    "target": "http://xxx.xxx.xxx.xxx:80/api/",  // API URL or any URL for Proxy
    "secure": false,
    "logLevel": "debug",
    "changeOrigin": true
  }
}

Step 2. then update angular.json file, Add property "proxyConfig" property at architect -> serve -> builder -> options -

"projects": {
        ...
        "angularPracticeProj": {
                "projectType": "application",
                "schematics": {},
                ...
                "architect": {
                        ...
                        "serve": {
                                ...
                                "builder": "@angular-devkit/build-angular:dev-server",
                                  "options": {
                                    "browserTarget": "angularPracticeProj:build",
                                    "proxyConfig": "proxy.conf.json"        <==== angular proxy
                                  },
                                ...
                                }
                        ...
                        }
                    }
            }
            
        

If you are working with NodeJS / ExpressJS REST API then update the app/root file from where you are loading express of nodejs-

Step 3(Optional). In nodejs or ExpressJS root file where - app root is defined add below code -

const app = express();
            // angular app set as start
            app.use(express.static(process.cwd() + "/../dist/angularPracticeProj/")); <= angular project's published/dist index file path
            app.get('/', (req, res) => {
            res.sendFile(process.cwd() + "/../dist/angularPracticeProj/index.html")   <= angular project's published/dist index file path
    });
Ravindra Vairagi
  • 1,055
  • 15
  • 22
0

Same issue occur to me as well for my Angular app with base url and i got the solution by adding parameter for base_href.

We need to specify the Angular app to use the base url by changing package.json in 'start' command by adding --base-href=/your-application-url/

    "start": "ng serve --proxy-config proxyconfig.json --deploy-url=/your-application-baseurl/ --base-href=/your-application-baseurl/"

"Package.json" after addition will be

    {
"name": "default",
"version": "0.0.0",
"license": "MIT",
"scripts": {
    "ng": "ng",
    "start": "ng serve --proxy-config proxyconfig.json --deploy-url=/your-application-baseurl/ --base-href=/your-application-baseurl/",
    "build": "ng build --prod",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
},
Rachit
  • 61
  • 1
  • 3