Ошибка 404 при вызове API, хотя количество запросов увеличивается - PullRequest
0 голосов
/ 12 декабря 2018

Это полностью отделено от Не удается найти модуль @ angular / core , хотя у меня все еще есть этот пакет решений на случай, если у кого-то есть идеи.

Так что у меня есть сайт Angular7 ипроект веб-API в том же решении.Я установил IIS Express для использования только порта 5000;Узел будет использовать порт 4200. В проекте веб-API я создал новый контроллер "AccountController", модель "LoginAttempt" и модель "LoginResult".

На угловой стороне у меня есть логинФайлы .component.html, login.component.ts, login.service.ts и serviceCall.service.ts.Файл login.component.ts обновляется html-файлом и передает запрос в файл login.service.ts, который упаковывает вещи и отправляет в файл serviceCall.service.ts для отправки в API.

Что происходит при попытке вызова, так это то, что я получаю сообщение об ошибке 404, но Visual Studio увеличивает значение «запросов», связанное с вызовом входа в систему.Кажется, я не могу найти причину, почему я получил бы 404 и все еще имел бы приращение запроса при попытке вызова.

Исходный код: C # Web API: Startup.cs

   public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseMvc();
        }
    }

LoginAttempt.cs

[Serializable]
public class LoginAttempt
{
    public string username { get; set; }
    public string password { get; set; }
}

LoginResult.cs

[Serializable]
public class LoginResult
{
    public string token { get; set; }
    public string message { get; set; }
    public bool success { get; set; }
}

AccountController.cs

[Route("api/[controller]")]
public class AccountController : Controller
{
    Account accountRepo = new Account();

    [HttpPost]
    public LoginResult Login(LoginAttempt input)
    {
        return accountRepo.verifyCredentials(input.username, input.password);
    }

    public IActionResult Index()
    {
        return View();
    }
}

Angular7 proxy.conf.json

{
  "exclude": [
    "**/bin",
    "**/bower_components",
    "**/jspm_packages",
    "**/node_modules",
    "**/obj",
    "**/platforms"
  ],
  "/api": {
    "target": "http://localhost:5000",
    "secure": false
  }
}

angular.json

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "smart-goal": {
      "root": "",
      "sourceRoot": "src",
      "projectType": "application",
      "prefix": "app",
      "schematics": {},
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist/smart-goal",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "src/tsconfig.app.json",
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ],
            "styles": [
              "src/styles.css"
            ],
            "scripts": []
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "extractCss": true,
              "namedChunks": false,
              "aot": true,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true,
              "budgets": [
                {
                  "type": "initial",
                  "maximumWarning": "2mb",
                  "maximumError": "5mb"
                }
              ]
            }
          }
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "smart-goal:build",
            "proxyConfig": "proxy.conf.json"
          },
          "configurations": {
            "production": {
              "browserTarget": "smart-goal:build:production"
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "smart-goal:build"
          }
        },
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "options": {
            "main": "src/test.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "src/tsconfig.spec.json",
            "karmaConfig": "src/karma.conf.js",
            "styles": [
              "src/styles.css"
            ],
            "scripts": [],
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ]
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": [
              "src/tsconfig.app.json",
              "src/tsconfig.spec.json"
            ],
            "exclude": [
              "**/node_modules/**"
            ]
          }
        }
      }
    },
    "smart-goal-e2e": {
      "root": "e2e/",
      "projectType": "application",
      "prefix": "",
      "architect": {
        "e2e": {
          "builder": "@angular-devkit/build-angular:protractor",
          "options": {
            "protractorConfig": "e2e/protractor.conf.js",
            "devServerTarget": "smart-goal:serve"
          },
          "configurations": {
            "production": {
              "devServerTarget": "smart-goal:serve:production"
            }
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": "e2e/tsconfig.e2e.json",
            "exclude": [
              "**/node_modules/**"
            ]
          }
        }
      }
    }
  },
  "defaultProject": "smart-goal"
}

LoginCredentials.ts

export class LoginCredentials {
  username: string | undefined;
  password: string | undefined;
}

LoginResults.ts

export interface ILoginResult {
  token: string,
  message: string,
  success: boolean
}

login.component.html

<p>Login Page</p>
<form>
  <label>Username:</label>
  <input type="text" [(ngModel)]="Username" name="Username"/>
  <label>Password:</label>
  <input type="password" [(ngModel)]="Password" name="Password"/>
  <button type="submit" (click)="LoginAttempt()">Submit</button>
</form>

login.component.ts

import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { Input } from '@angular/core';
import { LoginCredentials } from '../models/loginCredentials';
import { LoginService } from './login.service';

@Component({
  selector: 'login',
  templateUrl: './login.component.html'
})
export class LoginComponent {
  private router: Router;
  private Username: string;
  private Password: string;
  private Login: LoginCredentials;
  private response: undefined;
  private service: LoginService;

  constructor(router: Router, service: LoginService) {
    this.router = router;
    this.Login = new LoginCredentials();
    this.service = service;
    this.Username = "";
    this.Password = "";
  }

  LoginAttempt() {
    let data = new LoginCredentials();
    data.username = this.Username;
    data.password = this.Password;

    this.service.Login(data)
      .subscribe(
        result => {
          let response = JSON.stringify(result);
          alert("SUCCESS - " + response);
        }
      );
  }
}

login.service.ts

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { LoginCredentials } from '../models/LoginCredentials';
import { ServiceCall } from '../shared/serviceCall.service';
import { ILoginResult } from '../models/LoginResult';
import { map } from 'rxjs/operators';

@Injectable()
export class LoginService {
  call: ServiceCall;
  constructor(call: ServiceCall) {
    this.call = call;
  }

  public Login(loginAttempt: LoginCredentials): Observable<any> {
    let myResponse = new Map<string, string>()
    let data = new Map<string, string>();
    let data2 = new Map<string, string>();
    let url = "Account/Login";
    data.set('Username', loginAttempt.username);
    data.set('Password', loginAttempt.password);
    return this.call.makeCall(url, 'POST', data).pipe(map(response => data2 = response));
  }
}

serviceCall.service.ts

import { Injectable } from '@angular/core';
import { HttpClient, HttpParams, HttpHeaders, HttpRequest, HttpResponse,  } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

@Injectable()
export class ServiceCall {
  private _http: HttpClient;
  private _urlAppend: string;
  private _isAuthenticated: boolean;

  constructor(http: HttpClient) {
    this._http = http;
    this._urlAppend = '/api/';
    this._isAuthenticated = false;
  }

  public makeCall(url: string, type: string, data: Map<string, string>): Observable<any> {
    url = this._urlAppend + url;
    let headers = new HttpHeaders();
    headers.append('Content-Type', 'application/json');
    headers.append('charset', 'utf-8');
    let params = new HttpParams();
    let result = new Response();

    data.forEach((value: string, key: string) => {
      params.set(key, value);
    });

    let options = { headers: headers, params: params, withCredentials: this._isAuthenticated };
    let body = JSON.stringify(data);

    if (type == "GET") {
      return this._http
        .get(url, options)
        .pipe(map((result: Response) => result));
    } else if (type == "POST") {
      return this._http
        .post(url, body, options)
        .pipe(map(this.extractData));
    } else {
      Observable.throw("Invalid command.");
    }
  }

  public setAuthentication(input: boolean) {
    this._isAuthenticated = input;
  }

  private extractData(res: Response) {
    let body = res.json();
    return body || {};
  }

  private generateQueryString(input: Map<string, string>) {
    let response = new URLSearchParams();

    input.forEach((value: string, key: string) => {
      response.append(key, value);
    });

    return response;
  }
}

И, наконец, 404ответ, который отображается в консоли Chrome:

HttpErrorResponse
{
    error: null
    headers: HttpHeaders
    {
        lazyInit: f()
        lazyUpdate: null
        normalizeNames: Map(0) {}
    }
    message:  "Http failure response for http://localhost:4200/api/Acocunt/Login: 404 Not Found"
    name:  "HttpErrorResponse"
    ok:  false
    status: 404
    statusText:  "Not Found"
    url:  "http://localhost:4200/api/Account/Login"
}

1 Ответ

0 голосов
/ 13 декабря 2018

Тьфу.Проблемы с этим.Во-первых, на стороне C #: я привык к более старому веб-API с «обычной» структурой .NET, и при использовании .NET Core произошли некоторые изменения.В файле AccountController.cs "ветвь" для этого контроллера должна быть указана прямо над объявлением класса, чтобы иметь что-то вроде [Route("api/[controller]")] прямо над объявлением класса.Затем для каждого метода в классе я должен был определить, какой был URL-адрес этого конкретного метода.В приведенном выше случае

[HttpPost]
public LoginResult Login(LoginAttempt input)

должен был выглядеть так:

[Route("login")]
[HttpPost]
public IActionResult Login([FromBody]LoginAttempt input)

А затем на стороне Typescript сайт Angular2 игнорировал информацию прокси и не пыталсяжду моего порта API.В моем файле proxy.conf.json мне нужно, чтобы информация о моем прокси была похожа на следующую:Это.Это позволило мне работать так, как должно.

...