2
votes

So i'm creating a login screen for an app I am building. I've built and tested the login API and it works fine in a normal web application. In my angular-nativescript project however, it's not working at all and I can't figure out why. I think the reason is because it's just not doing the post request (because I have console logs in the function but I'm not seeing them, i'm just seeing the error console log)

I have tested it in postman and it works, it is getting the user input data through the [ngModel] and sending it with the post request but i'm not sure whats happening after that.

I have also updated the API URL so it will work with the locally hosted api (have tested if the API works through get requests in other sections of the app and it does so this isn't the problem)

i've attached an image of my screen so you can see what i'm doing and the response in the console. I have also attached an image of the actual response in postman (it should return a token string)postman imageenter image description here

This is the code (this is similar code as in an angular web application and it works there):

login.component.html

<StackLayout class="form">
  <StackLayout class="input-field">
    <TextField [(ngModel)]='username'></TextField>
  </StackLayout>

  <StackLayout class="input-field">
    <TextField [(ngModel)]='password'></TextField>
  </StackLayout>

  <Button text="Log In" class="btn btn-primary" (tap)="login()"></Button>
</StackLayout>

loggedInService.ts: (not sure if this will help but here are my imports for HTTP and RXJS):

import { HttpClient } from '@angular/common/http';
import { map } from 'rxjs/operators';

login(model: any) {
    return this.http.post(this.baseUrl + 'login', model)
        .pipe(
            map((response: any) => {
                console.log(response)
                const user = response;
                if (user) {
                    this.un = user.username;
                    console.log('USER = ', this.un);
                }
            })
        );
}

login.component.ts

username: any
password: any


login() {
    let model = {
        "username": this.username,
        "password": this.password
    }
    console.log(JSON.stringify(model))
    this.loggedInService.login(model).subscribe(next => {
        console.log('Logged in successfully');
    }, error => {
        console.log('Failed to login');
    });
}

[EDIT]

After some more testing, this may be an API issue. I'm not sure if it is but im getting a different response from the API when sending the request from postman to when I send it from nativescript. The API is build using .net core

In the response below it says

Connection id "0HLT9HL1GMPV1" bad request data: "Invalid request line: '\x16\x03\x01\x00\xFB\x01\x00\x00\xF7\x03\x03\x82`\xB2\x9Ex\x09`\x16\x0A'"

does this mean that i'm sending up the wrong type of information?

In the console when sending the post request to the API through the nativescript app, this is the response

info: Microsoft.AspNetCore.Server.Kestrel[17]
      Connection id "0HLT9HL1GMPV1" bad request data: "Invalid request line: '\x16\x03\x01\x00\xFB\x01\x00\x00\xF7\x03\x03\x82`\xB2\x9Ex\x09`\x16\x0A'"
Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException: Invalid request line: '\x16\x03\x01\x00\xFB\x01\x00\x00\xF7\x03\x03\x82`\xB2\x9Ex\x09`\x16\x0A'
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpParser`1.RejectRequestLine(Byte* requestLine, Int32 length)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpParser`1.GetUnknownMethod(Byte* data, Int32 length, Int32& methodLength)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpParser`1.ParseRequestLine(TRequestHandler handler, Byte* data, Int32 length)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpParser`1.ParseRequestLine(TRequestHandler handler, ReadOnlySequence`1& buffer, SequencePosition& consumed, SequencePosition& examined)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpParser`1.Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.IHttpParser<TRequestHandler>.ParseRequestLine(TRequestHandler handler, ReadOnlySequence`1& buffer, SequencePosition& consumed, SequencePosition& examined)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1Connection.TakeStartLine(ReadOnlySequence`1 buffer, SequencePosition& consumed, SequencePosition& examined)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1Connection.ParseRequest(ReadOnlySequence`1 buffer, SequencePosition& consumed, SequencePosition& examined)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1Connection.TryParseRequest(ReadResult result, Boolean& endConnection)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequestsAsync[TContext](IHttpApplication`1 application)

This is the result from when I send the request in postman

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 POST http://localhost:5000/api/auth/login application/json 49
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[1]
      Failed to validate the token.
Microsoft.IdentityModel.Tokens.SecurityTokenExpiredException: IDX10223: Lifetime validation failed. The token is expired. ValidTo: '09/15/2019 15:46:17', Current time: '02/04/2020 16:22:25'.  
   at Microsoft.IdentityModel.Tokens.Validators.ValidateLifetime(Nullable`1 notBefore, Nullable`1 expires, SecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateLifetime(Nullable`1 notBefore, Nullable`1 expires, JwtSecurityToken jwtToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateTokenPayload(JwtSecurityToken jwtToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
   at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[7]
      Bearer was not authenticated. Failure message: IDX10223: Lifetime validation failed. The token is expired. ValidTo: '09/15/2019 15:46:17', Current time: '02/04/2020 16:22:25'.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3]
      Route matched with {action = "Login", controller = "Auth"}. Executing controller action with signature System.Threading.Tasks.Task`1[Microsoft.AspNetCore.Mvc.IActionResult] Login(cartalk.api.Dtos.users.UserForLoginDto) on controller cartalk.api.Controllers.AuthController (cartalk.api).
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
      Executing action method cartalk.api.Controllers.AuthController.Login (cartalk.api) - Validation state: Valid
info: Microsoft.EntityFrameworkCore.Infrastructure[10403]
      Entity Framework Core 2.1.11-servicing-32099 initialized 'DataContext' using provider 'Microsoft.EntityFrameworkCore.Sqlite' with options: None
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      PRAGMA foreign_keys=ON;
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (0ms) [Parameters=[@__username_0='?' (Size = 5)], CommandType='Text', CommandTimeout='30']
      SELECT "x"."Id", "x"."Bio", "x"."Email", "x"."Followers", "x"."Following", "x"."PasswordHash", "x"."PasswordSalt", "x"."Username", "x"."isAdmin"
      FROM "Users" AS "x"
      WHERE "x"."Username" = @__username_0
      LIMIT 1
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
      Executed action method cartalk.api.Controllers.AuthController.Login (cartalk.api), returned result Microsoft.AspNetCore.Mvc.OkObjectResult in 2.0925ms.
info: Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor[1]
      Executing ObjectResult, writing value of type '<>f__AnonymousType0`1[[System.String, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]'.        
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
      Executed action cartalk.api.Controllers.AuthController.Login (cartalk.api) in 2.7807ms
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 3.6262ms 200 application/json; charset=utf-8

That is the response i'm looking for when sending the request from the nativescript app.

1
Did you try logging the error object or intercept the request in Chrome debugger? - Manoj
1.) In the second screenshot you are making non-secure HTTP call (to the localhost but still a non-secure one) which is forbidden by default for the newer android versions - see here. - Nick Iliev
2.) Make sure you are importing the NativeScriptHttpClientModule as shown in the documentation. Example here github.com/NickIliev/nativescript-ng-cosmos/blob/master/app/… - Nick Iliev
The NativeScriptHttpClientModule is imported like it shows there and in the rest of the app I am making non-secure HTTP get requests and I am not running into this problem - joshua chumber

1 Answers

0
votes

I figured it out, there was a problem with the post request that I was sending, I think it works differently in nativescript-angular to how it does in regular angular. There was also no error in the API

This is the new working code in case anyone else runs into this problem:

html

<StackLayout class="form">
  <StackLayout class="input-field">
    <TextField [(ngModel)]='model.username'></TextField>
  </StackLayout>

  <StackLayout class="input-field">
    <TextField secure="true" [(ngModel)]='model.password'></TextField>
  </StackLayout>

  <Button text="Log In" class="btn btn-primary" (tap)="submit()"></Button>
</StackLayout>

.ts

model: any = {};

ngOnInit() {
}

public submit() {
    console.log(this.model)
    this.makePostRequest();
}

private makePostRequest() {
    this.loggedInService
        .postData(this.model)
        .subscribe(res => {
            // this.message = (<any>res).json.data.username;
            console.log(res)
        });
}

service

    private serverUrl = environment.apiUrl + 'auth/login';

    postData(data) {
        let options = this.createRequestOptions();
        return this.http.post(this.serverUrl, data, { headers: options });
    }

    private createRequestOptions() {
        let headers = new HttpHeaders({
            "Content-Type": "application/json"
        });
        return headers;
    }