Docker中ASP.NET Core服务无法响应API请求求助
问题描述
使用docker-compose运行.NET 7应用时出现异常:调试日志无报错,显示应用已在对应端口运行,但访问Swagger时,虽能正常显示所有控制器端点,但发起请求后无响应,一直处于“加载”状态。
相关代码
Program.cs
var builder = WebApplication.CreateBuilder(args); builder.Services.AddTransient<TokenValidationMiddleware>(); builder.Services.AddHttpClient(); builder.Services.AddStackExchangeRedisCache(r => { r.Configuration = builder.Configuration["redis:connectionString"]; }); builder.Services.AddCors(); builder.Services.AddScoped<IUserContext, UserContext>(); builder.Services.AddControllers() .AddJsonOptions(options => { options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); }); builder.Services.AddDbContext<ApplicationDbContext>(options => { options.UseSqlServer(builder.Configuration.GetConnectionString("ConnectionString")).UseLazyLoadingProxies(); }); builder.Services.AddIdentityCore<ApplicationUser>(opt => { opt.Password.RequireNonAlphanumeric = false; }) .AddRoles<ApplicationRole>() .AddRoleManager<RoleManager<ApplicationRole>>() .AddSignInManager<SignInManager<ApplicationUser>>() .AddRoleValidator<RoleValidator<ApplicationRole>>() .AddEntityFrameworkStores<ApplicationDbContext>(); builder.Services.AddRouting(options => { options.LowercaseUrls = true; options.LowercaseQueryStrings = true; }); builder.Services.AddSingleton<SymmetricSecurityKey>(provider => { return new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]!)); }); builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(... }); builder.Services.AddAuthorization(opt => { }); builder.Services.AddScoped<IDbInitializer, DbInitializer>(); builder.Services.AddAutoMapper(x => x.AddMaps(Assembly.GetExecutingAssembly())); builder.Services.AddScoped(provider => new MapperConfiguration(cfg => { cfg.AddProfile(new AutoMapperProfiles(provider.GetService<ITokenService>()!)); }).CreateMapper()); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "web server api", Version = "v1" }); c.SchemaFilter<EnumSchemaFilter>(); }); builder.Services.AddHttpContextAccessor(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); app.UseCors(builder => { builder.AllowAnyOrigin(); builder.AllowAnyMethod(); builder.AllowAnyHeader(); }); } app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthentication(); app.UseMiddleware<TokenValidationMiddleware>(); app.UseAuthorization(); app.MapControllers(); using (var scope = app.Services.CreateScope()) { var dbInitializer = scope.ServiceProvider.GetRequiredService<IDbInitializer>(); dbInitializer.Initialize(); } app.Run();
DockerFile
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base WORKDIR /app EXPOSE 80 EXPOSE 443 FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build WORKDIR /src COPY ["proj.csproj", "."] RUN dotnet restore "./proj.csproj" COPY . . WORKDIR "/src/." RUN dotnet build "proj.csproj" -c Release -o /app/build FROM build AS publish RUN dotnet publish "proj.csproj" -c Release -o /app/publish /p:UseAppHost=false FROM base AS final WORKDIR /app COPY --from=publish /app/publish . ENTRYPOINT ["dotnet", "proj.dll"]
docker-compose-override.yml
version: '3.4' services: tokendb: container_name: tokendb restart: always ports: - "6379:6379" db: container_name: sqlserver environment: ACCEPT_EULA: 'Y' MSSQL_SA_PASSWORD: 'Test' MSSQL_PID: 'Developer' MSSQL_USER: 'test' restart: always ports: - '1433:1433' proj: environment: - ASPNETCORE_ENVIRONMENT=Development - "ConnectionStrings__ConnectionString=Server=db;Database=db;User Id=test;Password=Test;MultipleActiveResultSets=true;TrustServerCertificate=true" - "redis__connectionString=tokendb" depends_on: - db - tokendb ports: - "8002:80"
launchsettings.json
{ "profiles": { "Docker": { "commandName": "Docker", "launchBrowser": true, "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger", "publishAllPorts": true, "useSSL": true } } }
Docker日志
warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60] Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed. warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35] No XML encryptor configured. Key {f90133af-ea02-45ca-bc10-878b34233e36} may be persisted to storage in unencrypted form. info: Microsoft.Hosting.Lifetime[14] Now listening on: http://[::]:80 info: Microsoft.Hosting.Lifetime[0] Application started. Press Ctrl+C to shut down. info: Microsoft.Hosting.Lifetime[0] Hosting environment: Development info: Microsoft.Hosting.Lifetime[0] Content root path: /app
排查与解决建议
1. 调整中间件顺序
CORS中间件位置错误,当前仅在Development块内且顺序靠后,无法正确处理跨域请求。修改请求管道顺序:
if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseRouting(); // 将CORS移至此处,确保在路由之后、认证之前执行 app.UseCors(builder => { builder.AllowAnyOrigin(); builder.AllowAnyMethod(); builder.AllowAnyHeader(); }); app.UseAuthentication(); app.UseMiddleware<TokenValidationMiddleware>(); app.UseAuthorization();
2. 修复数据库初始化与连接问题
depends_on仅保证容器启动顺序,不保证SQL Server服务就绪。在DbInitializer.Initialize()中添加重试逻辑,避免初始化卡住:
public async Task Initialize() { int retryCount = 5; var delay = TimeSpan.FromSeconds(10); while (retryCount > 0) { try { await _context.Database.MigrateAsync(); // 其他初始化逻辑 break; } catch (SqlException) { retryCount--; if (retryCount == 0) throw; await Task.Delay(delay); } } }
- SQL Server容器默认不会自动创建
test用户,修改连接字符串使用SA账号:
- "ConnectionStrings__ConnectionString=Server=db;Database=db;User Id=sa;Password=Test;MultipleActiveResultSets=true;TrustServerCertificate=true"
3. 检查自定义中间件逻辑
确保TokenValidationMiddleware使用异步模式,避免同步阻塞请求:
public async Task InvokeAsync(HttpContext context) { // 所有IO操作需使用异步方法 await _next(context); }
同时验证Redis连接字符串是否包含必要参数(如密码),避免连接超时。
4. 调整HTTPS配置
launchsettings.json中开启了useSSL,但容器仅映射80端口,导致HTTPS请求失败。可二选一:
- 关闭开发环境的HTTPS重定向:
if (!app.Environment.IsDevelopment()) { app.UseHttpsRedirection(); }
- 配置容器HTTPS证书并映射443端口:
proj: environment: - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http://+:80;https://+:443 - ASPNETCORE_Kestrel__Certificates__Default__Password=yourcertpassword - ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx ports: - "8002:80" - "8003:443" volumes: - ${USERPROFILE}/.aspnet/https:/https:ro
5. 启用详细日志排查
在appsettings.Development.json中添加详细日志配置,查看请求过程中的隐藏异常:
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Debug" } } }
内容的提问来源于stack exchange,提问作者Jbtf
相关产品推荐
相关产品推荐

