You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

本地Docker容器化ASP.NET Core 9后端无法与React前端通信

React + ASP.NET Core 9 容器化后前后端通信失败问题

我开发了一个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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 11:09:58