【问题标题】:ASP Core Concurrent Requests Blocking at CORS PreflightASP 核心并发请求在 CORS 预检时阻塞
【发布时间】:2019-01-18 23:23:48
【问题描述】:

我有一个脚本可以向包含 JSON 的端点发送多个 POST。目前,该脚本可能会同时从 localhost 发出 100 多个 POST。在请求所有 POST 之前,不会调用该路由的方法;在此之前,只有 HTTP OPTIONS(CORS 预检)作为响应发送。一旦脚本停止发出 POST 请求,服务器才会开始调用路由方法。

当然,让脚本同时发出 100 多个 POST 请求会有所改变,但我担心这将如何影响许多用户的生产使用。

在我的调试中,我发现在该批次中的所有 POST 请求都发出之前,我的过滤器/代码都不会运行。

我不知道如何解决这个问题。 CPU 和内存甚至还没有接近极限,更改过滤器顺序没有效果,优化路由方法也没有效果,因为直到所有请求都发出后才会调用它。

我正在开发机器上使用 IIS Express 10 上的 Visual Studio 进行测试。我使用的是 ASP.NET Core 2.0。

应用配置:

    public void ConfigureServices(IServiceCollection services)
    {
        services
            .AddMvc()
            .AddJsonOptions(opt =>
            {
                opt.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc;
            })
            .AddMvcOptions(opt =>
            {
                opt.Filters.Add(new IPLoggingInterceptionAttribute());
            });

        services.AddCors(options =>
        {
            options.AddPolicy("AllOrigins", builder =>
            {
                builder.AllowAnyHeader();
                builder.AllowAnyMethod();
                builder.AllowAnyOrigin();
            });
        });

        services
            .AddScoped<RequireAuthAttribute>();

        String connectionString = Configuration.GetConnectionString("Vault");
        services.AddDbContext<VaultContext>(options => options.UseNpgsql(connectionString));
    }

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

        app.UseCors("AllOrigins");

        app.UseForwardedHeaders(new ForwardedHeadersOptions
        {
            ForwardedHeaders = ForwardedHeaders.All,
            RequireHeaderSymmetry = false
        });

        app.UseMvc();
    }

路由响应方法,以防相关:

    [HttpPost("{villageId}/army/current")]
    public async Task<IActionResult> PostCurrentArmy(long villageId, [FromBody]JSON.ArmySet currentArmySetJson)
    {
        if (!ModelState.IsValid)
            return ValidationProblem(ModelState);

        //  [Note that 'CurrentWorldId' is a blocking property on first read]
        //  Get or make CurrentVillage
        Scaffold.CurrentVillage currentVillage =
            await context.CurrentVillage
                .FromWorld(CurrentWorldId)
                .Where(v => v.VillageId == villageId)
                .FirstOrDefaultAsync();

        currentVillage = currentVillage ?? (await context.AddAsync(new Scaffold.CurrentVillage())).Entity;
        currentVillage.WorldId = CurrentWorldId;

        if (currentVillage.PlayerId == null)
        {
            var modelVillage = await (
                    from village in context.Village.FromWorld(CurrentWorldId)
                    where village.VillageId == villageId
                    select village
                ).FirstOrDefaultAsync();

            if (modelVillage != null)
            {
                currentVillage.VillageId = modelVillage.VillageId;
                currentVillage.PlayerId = modelVillage.PlayerId;
                currentVillage.Points = modelVillage.Points;
                currentVillage.VillageName = modelVillage.VillageName;
                currentVillage.X = modelVillage.X.Value;
                currentVillage.Y = modelVillage.Y.Value;
            }
        }

        if (!Configuration.Security.AllowUploadArmyForNonOwner
                && currentVillage.PlayerId != CurrentUser.PlayerId)
        {
            await context.InvalidDataRecord.AddAsync(MakeInvalidDataRecord(
                JsonConvert.SerializeObject(currentArmySetJson),
                $"Attempted to upload current army to village {villageId} but that village is not owned by the requestor"
            ));
            await context.SaveChangesAsync();
            return Unauthorized();
        }

        var fullArmy = currentArmySetJson.Stationed + currentArmySetJson.Traveling + currentArmySetJson.Supporting;
        currentVillage.ArmyOwned     = ArmyConvert.JsonToArmy(fullArmy, currentVillage.ArmyOwned, context);
        currentVillage.ArmyStationed = ArmyConvert.JsonToArmy(currentArmySetJson.Stationed, currentVillage.ArmyStationed, context);
        currentVillage.ArmyTraveling = ArmyConvert.JsonToArmy(currentArmySetJson.Traveling, currentVillage.ArmyTraveling, context);


        await context.SaveChangesAsync();
        return Ok();
    }

【问题讨论】:

  • 你确定它不是阻塞的java脚本/浏览器?另请注意,IIS Express 不是真正的服务器,它用于开发
  • 这不应被Core App 阻止。与我们分享发送100+ 请求的script

标签: c# asp.net-core cors


【解决方案1】:

正如@Tseng 指出的那样,在 IIS 服务器(非开发人员)上尝试一下。在您继续执行此操作之前,您应该能够快速完成以下几件事,以排除您的应用不是问题的原因。

  1. 您是否 100% 确定请求不会访问您的 netcore 应用程序?你可以吗 检查 IIS 日志并关联时间戳?最好有Fiddler 在您再次尝试以确保请求已安装之前已安装 实际上立即点击您的应用程序,而不是排队等候 大爆炸?

  2. 也尝试使用其他浏览器。使用所有优化浏览器 这些天用客户端代码做我有一些怪癖或 您提出请求的方式导致它以您的方式行事 如上所述(排队请求立即执行)。

如果上述两种情况并非如此,并且您可以确认所有请求都立即命中应用程序,那么我怀疑某种类型的阻塞和/或资源锁定会阻止所有请求排队。

让我们知道您的发现。祝你好运。

【讨论】:

    【解决方案2】:

    @Tseng 是正确的 - 问题在于浏览器,它似乎在脚本完成之前一直持有 POST 请求,但没有持有 OPTIONS 请求。

    【讨论】:

      猜你喜欢
      • 2020-12-14
      • 1970-01-01
      • 1970-01-01
      • 2015-09-29
      • 1970-01-01
      • 2012-02-24
      • 1970-01-01
      • 2012-11-08
      • 2021-08-26
      相关资源
      最近更新 更多