【问题标题】:Access to fetch from origin has been blocked by CORS policy, server api already supports middlewareCORS 策略阻止了从源获取的访问,服务器 api 已经支持中间件
【发布时间】:2020-06-10 15:38:49
【问题描述】:

我正在尝试让我的 ReactJS 应用程序(在 AWS S3 机器上)PUT 请求与我的服务器 API(在 AWS Windows EC2 机器上)一起工作。似乎我被发出的飞行前消息绊倒了。我一直在寻找如何处理这个问题并遇到了这两个 stackoverflow 帖子:

Enable OPTIONS header for CORS on .NET Core Web API

How to handle OPTION header in dot net core web api

我已确保 IIS 接受 OPTIONS 动词并添加了所描述的中间件。我可以看到通过日志记录调用了 OPTIONS 预检处理,但由于某种原因,我仍然收到 CORS 错误。列出了下面代码的主要部分,任何帮助将不胜感激。

ReactJS PUT 请求

    var myHeaders = new Headers();
    myHeaders.append('Accept', 'application/json');
    myHeaders.append('Content-Type', 'application/json-patch+json');

    var rawObject = {
      Name: this.state.recipeEdit.name,
      Type: this.state.recipeTypeEdit,
      Description: this.state.recipeEdit.description,
      Ingredients: this.state.recipeIngredients,
      Steps: this.state.recipeSteps,
    };

    var requestOptions = {
      method: 'PUT',
      headers: myHeaders,
      body: JSON.stringify(rawObject),
      redirect: 'follow',
    };

    fetch(this.state.url, requestOptions)
      .then((response) => response.json())
      .then((data) => {
        this.setState({ recipeDetail: data });
      });

中间件类

    public class OptionsMiddleware
    {
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        private readonly RequestDelegate _next;

        public OptionsMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public Task Invoke(HttpContext context)
        {
            return BeginInvoke(context);
        }

        private Task BeginInvoke(HttpContext context)
        {
            if (context.Request.Method == "OPTIONS")
            {
                log.Error("Handling the OPTIONS preflight message");

                context.Response.Headers.Add("Access-Control-Allow-Origin", new[] { (string)context.Request.Headers["Origin"] });
                context.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "Origin, X-Requested-With, Content-Type, Accept" });
                context.Response.Headers.Add("Access-Control-Allow-Methods", new[] { "GET, POST, PUT, DELETE, OPTIONS" });
                context.Response.Headers.Add("Access-Control-Allow-Credentials", new[] { "true" });
                context.Response.StatusCode = 200;
                return context.Response.WriteAsync("OK");
            }

            log.Error("Invoking message");
            return _next.Invoke(context);
        }
    }

    public static class OptionsMiddlewareExtentions
    {
        public static IApplicationBuilder UseOptions(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<OptionsMiddleware>();
        }
    }

Startup.cs 中的 CORS 配置

        public void ConfigureServices(IServiceCollection services)
        {
            log.Error("Entered ConfigureServices");

            try
            {
#if DEBUG
                services.AddCors();
#else
                services.AddCors(o => o.AddPolicy("MyCorsPolicy", builder =>
                {
                    builder.SetIsOriginAllowed((host) => true)
                           .AllowAnyMethod()
                           .AllowAnyHeader()
                           .AllowCredentials();
                }));
#endif

                services.AddControllersWithViews().AddNewtonsoftJson();

                services.AddControllersWithViews(options =>
                {
                    options.InputFormatters.Insert(0, GetJsonPatchInputFormatter());
                });

                services.AddMvc(options => options.EnableEndpointRouting = false).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
                services.AddMvc(options => options.Filters.Add(typeof(homebakeExceptionFilter)));

#if USE_SQLITE
                log.Error("Using SQLITE");
                services.AddDbContext<SqliteDbContext>(options =>
                {
                    options.UseSqlite("Data Source=./homebake.db");
                });
#else
            services.AddDbContext<AppDbContext>(options =>
            {
                options.UseInMemoryDatabase("homebakeapp-api-in-memory");
            });
#endif
                log.Error("Adding services");
                services.AddScoped<IIngredientRepository, IngredientRepository>();
                services.AddScoped<IRecipeStepRepository, RecipeStepRepository>();
                services.AddScoped<IRecipeRepository, RecipeRepository>();
                services.AddScoped<IIngredientService, IngredientService>();
                services.AddScoped<IRecipeStepService, RecipeStepService>();
                services.AddScoped<IRecipeService, RecipeService>();
                services.AddScoped<IUnitOfWork, UnitOfWork>();

                log.Error("Adding auto mapper");
                services.AddAutoMapper(typeof(Startup));
            }
            catch (System.Exception ex)
            {
                log.Error(ex.Message);
                if (ex.InnerException != null )
                    log.Error(ex.InnerException);
            }
        }

        private static NewtonsoftJsonPatchInputFormatter GetJsonPatchInputFormatter()
        {
            var builder = new ServiceCollection()
                .AddLogging()
                .AddMvc()
                .AddNewtonsoftJson()
                .Services.BuildServiceProvider();

            return builder
                .GetRequiredService<IOptions<MvcOptions>>()
                .Value
                .InputFormatters
                .OfType<NewtonsoftJsonPatchInputFormatter>()
                .First();

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
        {
            loggerFactory.AddLog4Net();

            log.Error("Entered Configure");
            app.UseOptions();

#if DEBUG
            app.UseCors(options => options.WithOrigins("http://localhost:3000").AllowAnyMethod().AllowAnyHeader());
#else
            log.Error("Using cors policy");
            app.UseCors("MyCorsPolicy");
#endif

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                app.UseHsts();
            }
            //app.use
            app.UseHttpsRedirection();

            log.Error("Using MVC");
            app.UseMvc();
        }

【问题讨论】:

    标签: reactjs .net-core cors


    【解决方案1】:

    当使用 web.config 和代码(例如在中间件中)设置服务器端 CORS 设置时,我看到了此错误,这在运行时会导致重复并导致此类行为。此外,您可能希望将以下内容添加到您的 web.config 中,看看是否有帮助。这将确保您的 CORS 设置仅由代码设置。

    <httpProtocol>
        <customHeaders>
            <remove name="Access-Control-Allow-Headers" />
            <remove name="Access-Control-Allow-Methods" />
            <remove name="Access-Control-Allow-Origin" />        
        </customHeaders>
    </httpProtocol>
    

    【讨论】:

    • 感谢您,看起来我没有复制 CORS 设置,但我将代码添加到了 web.config。我在中间件中添加了进一步的日志记录以输出已添加的标头,它看起来只是中间件代码中配置的标头。有没有办法确定响应的哪一部分导致失败?
    • 为了更深入的调试,我会在WebApiConfig.cs 文件的Register 方法中添加config.EnableSystemDiagnosticsTracing();。有关此功能的更多信息:docs.microsoft.com/en-us/aspnet/web-api/overview/… 至于 CORS 问题,如果尚未完成,我还将在相同的方法中添加 config.EnableCors(); Register
    • 再次感谢马苏德。您能否澄清一下,这些调用是基于 ASP.Net 还是 .Net Core?我正在使用 .Net Core,但没有任何注册方法。
    • 好的,所以我今晚又在看这个了。我收到的错误是请求的资源上没有 Access-Control-Allow-Origin 标头,但是如果我将 添加到我的web.config 文件我收到一条错误消息,指出 Access-Control-Allow-Origin 标头中不能有多个条目。是我还是发生了其他事情?
    • 我的输入基于 ASP.NET,但我怀疑根本原因可能是相同的,因为您看到的错误与我看到的类似。它抱怨“多个条目”的事实表明这些 CORS 设置中可能存在多个一个或多个。
    【解决方案2】:

    最终问题与 IIS 配置有关。经过更多搜索,我在这里找到了解决方案:

    How do I enable HTTP PUT and DELETE for ASP.NET MVC in IIS?

    基本上我必须更新 ExtensionlessUrlHandler-Integrated-4.0 设置以接受 PUT 和 DELETE 动词(从 IIS 中的 Handler Mappings 选项访问它)并同时禁用 WebDav 模块和处理程序。之后,请求通过并得到正确处理。我还在运行上面详述的中间件代码,以防其他人遇到此问题。

    让我查看 IIS 配置的原因是,如果我将 Access-Control-Allow-Origin 添加到我的 web.config 文件中,我得到了多个条目,如果是这样,如果不包含在其中,它怎么会丢失。非常感谢@Masoud Safi 在这方面提供的帮助。

    【讨论】:

      猜你喜欢
      • 2021-07-20
      • 2019-09-24
      • 2020-07-29
      • 2019-04-28
      • 1970-01-01
      • 2021-04-01
      • 2017-06-17
      • 2021-01-24
      • 2020-09-17
      相关资源
      最近更新 更多