本地Docker容器化ASP.NET Core 9后端无法与React前端通信
我开发了一个React前端搭配ASP.NET Core 9后端的Web应用,本地调试正常,但打包成Docker容器后(不管是本地运行还是VPS部署),前端都无法和后端通信。
现有配置信息
后端Dockerfile
# Use the official ASP.NET Core runtime as the base image FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base WORKDIR /app EXPOSE 5079 ENV ASPNETCORE_URLS=http://*:5079 # Install curl RUN apt-get update && apt-get install -y curl # Use the official ASP.NET Core SDK as the build image FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build WORKDIR /src # Copy the main project and reference projects COPY ["Drain.Server/Drain.Server.csproj", "Drain.Server/"] COPY ["Swmm/Swmm.csproj", "Swmm/"] # Restore dependencies RUN dotnet restore "Drain.Server/Drain.Server.csproj" # Copy all source files COPY Drain.Server/ Drain.Server/ COPY Swmm/ Swmm/ # Build the project WORKDIR /src/Drain.Server RUN dotnet build "Drain.Server.csproj" -c Release -o /app/build # Publish the project FROM build AS publish RUN dotnet publish "Drain.Server.csproj" -c Release -o /app/publish # Final stage to serve the application FROM base AS final WORKDIR /app COPY --from=publish /app/publish . ENTRYPOINT ["dotnet", "Drain.Server.dll"]
Docker Compose配置
services: frontend: build: context: ./drain.client dockerfile: Dockerfile args: - VITE_API_URL=http://drain-backend-container:5079/api image: xxx/stormstudio:dev0.2 container_name: drain-frontend-container ports: - "8080:80" environment: - VITE_API_URL=http://drain-backend-container:5079/api networks: - app-network backend: build: context: ./ dockerfile: Dockerfile args: - ASPNETCORE_URLS=http://*:5079 image: xxx/drain-backend:dev0.2 container_name: drain-backend-container ports: - "5079:5079" environment: - ASPNETCORE_URLS=http://*:5079 networks: - app-network networks: app-network: name: app-network driver: bridge
前端请求代码
const sendToServer = async (dataToSend: NetworkData): Promise<NetworkData> => { console.log(`env log: ${import.meta.env}`); const apiUrl = import.meta.env.VITE_API_URL; console.log(`API URL: ${apiUrl}`); try { const response = await axios.post( `${apiUrl}/compute`, //"http://localhost:5079/api/compute", dataToSend, { headers: { "Content-Type": "application/json", }, } ); const updatedData = response.data.updatedData; // Extract the updated data //console.log(updatedData); return updatedData; } catch (error) { console.error("Error sending data to the server:", error); throw new Error("Failed to fetch updated data"); } };
日志显示API URL为http://drain-backend-container:5079/api,符合预期。
后端控制器代码
[Route("api/compute")] [ApiController] public class ComputeController : ControllerBase { [HttpPost] public IActionResult PostData([FromBody] NetworkData data) { // Logic to handle the data, for example: // After processing, return the updated NetworkData return Ok(new { success = true, message = "Data received and processed", updatedData = data }); } } }
Program.cs配置
var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); // Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi builder.Services.AddOpenApi(); builder.Services.AddCors(options => { options.AddPolicy("AllowAll", policy => { policy.AllowAnyOrigin() // Allows all origins (can restrict to specific domains in production) .AllowAnyMethod() .AllowAnyHeader(); }); }); var app = builder.Build(); app.UseCors("AllowAll"); app.UseAuthorization(); app.UseDefaultFiles(); app.MapStaticAssets(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.MapOpenApi(); } app.UseHttpsRedirection(); app.MapControllers(); app.MapFallbackToFile("/index.html"); app.Run();
已确认信息
- 两个容器处于同一Docker网络
docker ps显示容器正常运行:
xxx/drain-backend:dev0.2 "dotnet Drain.Server…" 33 minutes ago Up 30 minutes 0.0.0.0:5079->5079/tcp drain-backend-container de7042f59878
xxx/stormstudio:dev0.2 "/docker-entrypoint.…" 33 minutes ago Up 33 minutes 0.0.0.0:8080->80/tcp drain-frontend-container
- 后端日志显示正常监听:
Application started. Press Ctrl+C to shut down.
//various other stuff
Now listening on: http://[::]:5079
排查与解决方案
1. 前端请求URL的核心问题
前端代码在浏览器环境运行,浏览器无法识别Docker容器名称drain-backend-container——这个名称仅在Docker内部网络可解析。当前配置的VITE_API_URL在浏览器中会被当作无效域名,导致请求失败。
修复方案:
- 本地测试:将
VITE_API_URL改为http://localhost:5079/api,利用后端容器映射的主机端口访问; - VPS部署:改为
http://<VPS公网IP>:5079/api,或绑定域名后使用域名地址。
2. 后端HTTPS重定向冲突
Program.cs中启用了app.UseHttpsRedirection();,但后端容器仅暴露HTTP端口5079,未配置HTTPS证书。前端发送的HTTP请求会被强制重定向到HTTPS,导致请求失败。
修复方案:
- 开发/测试环境:暂时注释
app.UseHttpsRedirection();; - 生产环境:配置ASP.NET Core的HTTPS证书(如Let's Encrypt),修改容器端口映射为
443:443,并更新前端API URL为HTTPS地址。
3. 容器内部连通性验证
进入前端容器,用curl测试后端接口,确认Docker内部网络是否正常:
# 进入前端容器 docker exec -it drain-frontend-container bash # 发送测试请求 curl http://drain-backend-container:5079/api/compute -X POST -H "Content-Type: application/json" -d '{}'
如果请求成功,说明Docker内部网络正常,问题出在浏览器环境;如果失败,检查后端容器是否真的监听5079端口,或是否存在防火墙/安全组限制。
4. 路由匹配验证
控制器路由[Route("api/compute")]+[HttpPost]对应路径/api/compute,前端请求的${apiUrl}/compute(apiUrl为http://xxx:5079/api)最终路径为http://xxx:5079/api/compute,路由匹配正常。可在前端打印完整请求URL,再次确认路径正确性。
内容的提问来源于stack exchange,提问作者Richard

