Azure 应用服务上的 ASP.NET Core Web API - POST 和 PUT 请求在短时间内失败 500

问题描述 投票:0回答:1

Web 应用程序是 REST API 和 SPA。它已得到维护,目前在 .NET 6.0 上运行,多年来一直稳定运行。

请求是 CORS,并且服务器已为此正确配置。

突然间,我们每天都会爆发几次

POST
PUT
请求,持续失败并出现 500 服务器错误。而且它们很快就会失败,只有 30 毫秒。这种情况持续 5-15 分钟,然后再次恢复正常。

所有

GET
请求在其间仍然工作得很好,这很奇怪。

更奇怪的是,这些失败的请求不会被记录下来,就像它们从未到达网络服务器一样。检查了 Web 服务器日志 (IIS) 和 ASP.NET Core 应用程序异常和跟踪。

这些失败的请求中也缺少响应标头

X-Powered-By: ASP.NET
。正常的 500 服务器错误会出现这种情况。 还表明请求永远不会到达服务器。

应用服务计划当前仅使用 30% 的资源。

Chrome、Edge 和 Safari 也证实了相同的行为。但是,您可能会在 Chrome 中遇到问题,而 Edge 中的会话在同一台 PC 上可以完美运行。

如果我们关闭浏览器并重新打开,问题就消失了。

这一切都从本月开始:2024 年 5 月

还值得一提的是,我们有一个 DNS 负载均衡器,Azure 流量管理器。

这只适用于 DNS 查询并返回 REST API 服务的两个实例中最接近的一个。

因此,流量管理器不会记录任何请求。

更新确认也发生错误没有流量管理器。

更新 2 我们已经测试了在全新应用服务上的部署。并尝试升级到.NET8.0。没有效果

这使得我们只能在浏览器的网络日志中进行检查。我们导出了许多 HAR 文件,并寻找失败请求和工作请求之间的差异,但没有发现任何差异。

有人经历过类似的行为吗?

Startup.cs
中ASP.NET Core的配置:

public class Startup
{
    readonly string _corsPolicyName = "corsOrigins";
    public IConfiguration Configuration { get; }
    public IWebHostEnvironment Environment { get; }

    private static IConfiguration config;
    public static IConfiguration GetConfiguration()
    {
        return config;
    }

    public Startup(IConfiguration configuration, IWebHostEnvironment environment)
    {
        Configuration = configuration;
        config = configuration;
        Environment = environment;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        if (Environment.IsDevelopment())
            IdentityModelEventSource.ShowPII = true;

        // logging
        services.AddApplicationInsightsTelemetry();
        services.AddLogging(logging => 
        {
            logging.AddSimpleConsole();
            logging.AddAzureWebAppDiagnostics();
        });
        services.Configure<AzureFileLoggerOptions>(options =>
        {
            options.FileName = "filelog-";
            options.FileSizeLimit = 50 * 1024;
            options.RetainedFileCountLimit = 5;
        });
        services.Configure<AzureBlobLoggerOptions>(options =>
        {
            options.BlobName = "Backend.txt";
        });

        // so our claims will not be translated
        JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

        // configure languages
        services.Configure<RequestLocalizationOptions>(options =>
        {
            var supportedCultures = new[]
            {
                new CultureInfo("en"),
                new CultureInfo("no")
            };
            options.DefaultRequestCulture = new RequestCulture("en");
            options.SupportedCultures = supportedCultures;
            options.SupportedUICultures = supportedCultures;
        });

        // add Identity
        services.AddIdentity<ApplicationUser, ApplicationRole>()
            .AddEntityFrameworkStores<AuthContext>()
            .AddRoleManager<RoleManager<ApplicationRole>>()
            .AddDefaultTokenProviders();
        services.AddUserAndPasswordPolicies();

        services.AddCors(options =>
        {
            {
                options.AddPolicy(_corsPolicyName, builder =>
                builder.SetIsOriginAllowedToAllowWildcardSubdomains()
                .WithOrigins("https://*.our.domain")
                .AllowAnyMethod()
                .AllowAnyHeader()
                .AllowCredentials());
            }
        });

        services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        }).AddJwtBearer(o =>
        {
            o.MapInboundClaims = false;
            o.Authority = Configuration.GetValue<string>("authServerUrl");
            o.Audience = "backend";
            o.RequireHttpsMetadata = true;
            o.SaveToken = true;
            o.TokenValidationParameters = new TokenValidationParameters
            {
                NameClaimType = "name",
                RoleClaimType = "role",
                ValidateIssuer = true,
                ValidateAudience = true
            };
        });

        services.AddControllersWithViews(options =>
        {
            options.Filters.Add<WebCustomExceptionFilter>();
        })
            .AddNewtonsoftJson(options =>
            {
                options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
            });

        services.AddSignalRManager();

        services.AddRazorPages()
            .AddRazorRuntimeCompilation();

        services.AddSwaggerGenNewtonsoftSupport();
        services.AddSwaggerGen(options =>
        {
            options.SwaggerDoc("v1", new OpenApiInfo { Title = "server debug api spec", Version = "v1" });
            options.SchemaFilter<EnumSchemaFilter>();
        });
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        StaticEnvironment.IsDebug = env.IsDevelopment();
        StaticEnvironment.ContentRootPath = env.ContentRootPath;

        app.UseCors(_corsPolicyName);

        if (env.IsDevelopment())
        {
            app.UseStaticFiles();
            app.UseDeveloperExceptionPage();
            app.UseSwagger();
            app.UseSwaggerUI(c => {
                c.DocumentTitle = "Backend Swagger docs";
                var sidebar = Path.Combine(env.ContentRootPath, "wwwroot/sidebar.html");
                c.HeadContent = File.ReadAllText(sidebar);
                c.InjectStylesheet("/colors.css");
                c.InjectStylesheet("/style.css");
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "server");
            });
        }
        else
        {
            app.UseHttpsRedirection();
            app.UseHsts();
        }

        // Localization
        app.UseRequestLocalization();
        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

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

        // Enable static files for use in MVC views. 
        app.UseStaticFiles();
        app.UseStaticFiles(new StaticFileOptions()
        {
            FileProvider = new PhysicalFileProvider(
                        Path.Combine(Directory.GetCurrentDirectory(), @"Style")),
            RequestPath = new PathString("/Style")
        });
    }
}

典型控制器签名:

[Authorize]
[ApiController]
[Route("api/[controller]")]
public class ImprovementController : ControllerBase

Web客户端获取代码

const fullUrl = `${baseUrl}/${url}`
const bearer = getBearer()
const connectionId = getConnectionId()
    
const req = {
    method: "POST",
    headers: {
        "Authorization": bearer,
        "Content-Type": "application/json"
    },
    body: JSON.stringify(data)
}
    
const res = await fetch(fullUrl, req)
rest asp.net-core cors azure-appservice
1个回答
0
投票

微软收到了几张罚单。请参阅https://learn.microsoft.com/en-us/answers/questions/1687258/our-azure-app-service-application-started-to-exper

我们有同样的问题,很多其他人也有。 Post 请求随机失败并出现 500 错误,而获取工作正常。一段时间后又可以工作了。显然可以通过将 HTTP/2 设置回 HTTP/1.1 来修复它

我希望在下周一所有客户都恢复工作时确认这一点

© www.soinside.com 2019 - 2024. All rights reserved.