【问题标题】:.Net 3.1 API & Angular 9 CORS with NGINX Proxy.Net 3.1 API 和 Angular 9 CORS 与 NGINX 代理
【发布时间】:2020-05-27 06:51:46
【问题描述】:

我遇到了从 Angular 9 UI Web 应用程序交换数据的问题。我知道该领域有很多主题,但我无法使其发挥作用,我将与您分享我的代码,看看我是否可以到达那里。我似乎找不到根本原因在哪里,如果它的 .Net API 配置错误、NGINX 或 Angular 应用程序。这是我的第一个“真正”解决方案,所以我仍在学习所有组件的方法。

我有一个 .Net 3.1 API 控制器,用于公开 MySQL Db 数据。 Angular 应用程序位于 NGIX 代理服务器部署的后面。

GET、PUT、POST、DELETE 请求来自 Postman 应用程序或导航到控制器地址。此外,GET 请求适用于 Angular 应用程序。但是,PUT、POST 请求不起作用。

我尝试修改 .NET API 启动配置,按照他们的教程添加来自 Microsoft 的 CORS Nugget 包,但没有成功。完成此操作后,GET 也停止工作。 执行 PUT / POST 请求时 Angular 应用程序出错:

从源“http://localhost:4200”对“http://192.168.10.40/api/AlertsConfig/”处的 XMLHttpRequest 的访问已被 CORS 策略阻止:对预检请求的响应未通过访问控制检查:没有“Access-Control-Allow-Origin”标头出现在请求的资源上。

我尝试了什么:

public void ConfigureServices(IServiceCollection services)
    {
        // ...

        // Add CORS policy
        services.AddCors(options =>
        {
            options.AddPolicy("test",
            builder =>
            {
                // Not a permanent solution, but just trying to isolate the problem
                builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();
            });
        });

        services.AddControllers();
    }
 public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseHttpsRedirection();

        // Use the CORS policy
        app.UseCors("test");

        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }

我的 .Net 控制器 - 为了简单起见,我只对 PUT 感兴趣

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using BeckerSmartFan.Data;
using BeckerSmartFan.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace BeckerSmartFan.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    [AllowAnonymous]
    public class AlertsConfigController : ControllerBase
    {
        private readonly ConnectionStrings con;
        private readonly Data.MySqlConnector mySqlConnector;

        public AlertsConfigController(ConnectionStrings c)
        {
            con = c;
            mySqlConnector = new Data.MySqlConnector();
        }

        // GET: api/AlertsConfig
        [HttpGet]
        public async Task<IActionResult> Get([FromQuery]  IEnumerable<AlertsConfig> alertsConfigs, [FromQuery] string type)
        {
            return await Task.Run(() =>
            {
                var listAlertConfigs = mySqlConnector.GetAllAlertsConfigs(con, type);
                return listAlertConfigs != null ? (IActionResult)Ok(listAlertConfigs) : NotFound();
            });
        }  

        // PUT: api/AlertsConfig/
        [HttpPut]
        public async Task<IActionResult> Put([FromBody] AlertsConfig alertConfig)
        {
            return await Task.Run(() =>
            {
                var result = mySqlConnector.UpdateAlertConfig(con, alertConfig);
                return result > 0 ? (IActionResult)Ok(alertConfig) : BadRequest();
            });
        }    

    }
}

我的 Angular Http 服务:

import { HttpClient, HttpErrorResponse, HttpParams } from '@angular/common/http';
import { catchError, map, timeout } from 'rxjs/operators';   
import {  throwError } from 'rxjs';   
import { NotFoundError } from '../common/not-found-error';
import { FanDataTag } from './FanDataTag';

const QueryTimeOut : number = 5000;

export class ApiDataService {
  constructor(private url: string, private http: HttpClient) {
    console.log("Contstructor:" + url);
   }

  getAll(startDate?:string, endDate?:string){

    if(typeof startDate === 'undefined' && typeof endDate === 'undefined')
    {
      return this.http.
                    get<any[]>
                    (
                      this.url
                    )
                    .pipe
                    (
                      catchError
                      (
                        this.handleError
                      )
                    , 
                      timeout
                      (
                        QueryTimeOut
                      )
                    );
    }
    else
    {     
      return this.http
                  .get<any[]>
                  ( 
                    this.url, 
                    {
                      params:
                      {
                        dateStart:startDate, 
                        dateEnd: endDate
                      }
                    }
                  )
                  .pipe
                  (
                    catchError
                    (
                      this.handleError
                    ), 
                    timeout(
                      QueryTimeOut
                      )
                  );
    }

  }

  getAlertsConfig(type?:string){

    if(typeof type === 'undefined')
    {
      return this.http.
                    get<any[]>
                    (
                      this.url
                    )
                    .pipe
                    (
                      catchError
                      (
                        this.handleError
                      )
                    , 
                      timeout
                      (
                        QueryTimeOut
                      )
                    );
    }
    else
    {     
      return this.http
                  .get<any[]>
                  ( 
                    this.url, 
                    {
                      params:
                      {
                        type:type                        
                      }
                    }
                  )
                  .pipe
                  (
                    catchError
                    (
                      this.handleError
                    ), 
                    timeout(
                      QueryTimeOut
                      )
                  );
    }

  }

  getLastRecord(getLastRecord?:boolean)
  {   
      return this.http.get<any[]>(this.url, { params:{
          dateStart:null, 
          dateEnd: null,  getLastRecord: getLastRecord.toString()}  }).pipe(timeout(QueryTimeOut)); 

  }

  getRecord(recordId?:number)
  {   
      return this.http.get<any[]>(this.url + "/" + recordId).pipe(timeout(QueryTimeOut));; 
  }


  create(resource: any){
    return this.http.post<any>(this.url , JSON.stringify(resource))
      .pipe(
        catchError(this.handleError));

  }     

  update(resource:any, isPatch:boolean)
  {

    if(isPatch)
    {
      return this.http.patch(this.url, JSON.stringify({isRead:true}))
        .pipe(
          catchError(this.handleError));
    }
    else
    {
      return this.http.put(this.url, resource );  
    }

  }


  delete(id: number){
    return this.http.delete(this.url+"/"+id)
      .pipe(
        catchError(this.handleError));
  }

  private handleError(error: HttpErrorResponse) {
    console.log(error);
    if (error.error instanceof NotFoundError) {
      // A client-side or network error occurred. Handle it accordingly.
      return throwError(
        'Bad request. Please refresh your page, and try again.');
    } 

    else {
      // The backend returned an unsuccessful response code.
      // The response body may contain clues as to what went wrong,
      return throwError(
      error.statusText + ": " + error.name );
    }

  };


}

NGINX 配置:

   server {
                listen 80 default_server;
                listen [::]:80 default_server;

        root /var/www/WebApp;

        # Add index.php to the list if you are using PHP
        index index.html index.htm index.nginx-debian.html;

        server_name _;

        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Credentials' 'true';
        add_header 'Access-Control-Allow-Headers' 'Content-Type,Accept';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';

  location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                try_files $uri $uri/ =404;
                proxy_pass         http://localhost:5000/;
                proxy_http_version 1.1;
                proxy_set_header   Upgrade $http_upgrade;
                proxy_set_header   Connection keep-alive;
                proxy_set_header   Host $host;
                proxy_cache_bypass $http_upgrade;
                proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header   X-Forwarded-Proto $scheme;

        }

          location /api/FanDataTags {
                proxy_pass         http://localhost:5000/api/FanDataTags;

         }

        location /api/AlertsConfig {
                proxy_pass http://localhost:5000/api/AlertsConfig;
        }
server {
        listen 8080;
        listen [::]:8080;

        server_name _;

        root /var/www/Angular;

        location / {
                #directory, then fall back to displaying a 404.
                try_files $uri $uri/ /index.html;
                index index.html index.htm;
                #proxy_pass         http://localhost:8080/;
                #proxy_http_version 1.1;
                #proxy_set_header   Upgrade $http_upgrade;
                #proxy_set_header   Connection keep-alive;
                #proxy_set_header   Host $host;
                #proxy_cache_bypass $http_upgrade;
                #proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
                #proxy_set_header   X-Forwarded-Proto $scheme;

        }
}

Chrome 中的网络标签:

【问题讨论】:

  • 我已经在我的计算机上(Angular App + API)本地尝试了所有东西,没有通过 NGINX。在 WEB API 中添加了 CORS Nugget 配置,一切正常。那么是我在 NGINX 中的问题吗?

标签: asp.net angular nginx controller


【解决方案1】:

我发现了问题,问题是我在两个不同的地方配置 CORS 策略,“安全胜于遗憾”的心态并不总是正确的。 NGINX CORS 和 .NET API CORS 配置发生冲突。

为每个方法或控制器添加 CORS 数据注解。

[EnableCors(origins: "", headers: "", methods: "*")]

并在 Startup.cs 上配置 CORS Microsoft Nugget 包。

    public class Startup
{
    readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddPolicy(name: MyAllowSpecificOrigins,
                              builder =>
                              {
                                  builder.WithOrigins("http://example.com",
                                                      "http://www.contoso.com");
                              });
        });

        services.AddControllers();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseRouting();

        app.UseCors(MyAllowSpecificOrigins);

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
}

或者使用任何你觉得更容易的 NGINX。

【讨论】:

    猜你喜欢
    • 2020-09-01
    • 2016-11-16
    • 2020-09-10
    • 1970-01-01
    • 2021-07-27
    • 2020-08-21
    • 2020-05-05
    • 1970-01-01
    • 2020-12-09
    相关资源
    最近更新 更多