Azure App Service上ASP.NET Core Web API的POST/PUT请求间歇性500错误排查
问题描述
我们的Web应用采用REST API+SPA架构,基于.NET 6.0稳定运行多年,CORS配置无误。自2024年5月起,每日多次出现POST/PUT请求快速返回500错误的情况,持续5-15分钟后自动恢复,期间GET请求完全正常。
排查情况
- 异常请求未被IIS及ASP.NET Core应用日志记录,且响应缺少正常500错误应有的
X-Powered-By: ASP.NET头,说明请求可能未到达服务器。 - 当前Azure App Service Plan资源使用率仅30%,排除资源耗尽问题。
- 问题在Chrome、Edge、Safari中均有出现,但同一设备上可能Chrome出问题而Edge正常,重启浏览器即可解决。
- 已确认移除Azure Traffic Manager后问题仍存在,部署至全新App Service、升级至.NET 8.0也无法解决。
- 导出HAR文件对比正常与异常请求,未发现差异。
相关代码
Startup.cs配置
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
前端fetch代码
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)
内容的提问来源于stack exchange,提问作者atlmag
相关产品推荐
相关产品推荐

