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

使用Ocelot作为API网关在Docker Compose中出现连接拒绝问题

问题描述

我正在基于Docker搭建包含多个.NET 8 API、Ocelot API网关与Angular前端的微服务架构。目前两个API服务可正常运行,Angular前端也能直接调用API获取数据。

为了在API与前端间加入网关,我选用Ocelot并配置了如下ocelot.json文件:

{"Routes": [{"DownstreamPathTemplate": "/api/v1/todos/tasks","DownstreamScheme": "http","DownstreamHostAndPorts": [{"Host": "todo.api","Port": "8080"}],"UpstreamPathTemplate": "/api/todos","UpstreamHttpMethod": ["Get"]},{"DownstreamPathTemplate": "/api/v1/food/recipes","DownstreamScheme": "http","DownstreamHostAndPorts": [{"Host": "food.api","Port": "5010"}],"UpstreamPathTemplate": "/api/recipes","UpstreamHttpMethod": ["Get"]}],"Aggregates": [],"GlobalConfiguration": {"BaseUrl": "http://localhost:5900"}}

随后我将所有服务加入Docker Compose配置:

version: '3.4'

services:
  todo.api:
    image: todoapi
    container_name: todo.api
    build:
      context: ./TestProject.Service.Todo
      dockerfile: ./Api/Dockerfile
    ports:
      - "5000:8080"
      - "5001:8081"
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
  todo.database:
    image: postgres:latest
    container_name: todo.database
    environment:
      - POSTGRES_DB=todos
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
    volumes:
      - ./.containers/todos-db:/var/lib/postgresql/data
    ports:
      - 5432:5432
  gateway.web:
    image: gatewayweb
    container_name: gateway.web
    build:
      context: ./TestProject.Gateway.Web
      dockerfile: ./Api/Dockerfile
    ports:
      - "5900:8080"
      - "5901:8081"
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
  dbbeaver:
    image: dbeaver/cloudbeaver
    ports: ["8000:8978"]
    hostname: gui
    container_name: dbeaver-container    

  food.api:
    image: foodapi
    container_name: food.api
    build:
      context: ./TestProject.Service.Food
      dockerfile: ./Api/Dockerfile
    ports:
      - "5010:8080"
      - "5011:8081"
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
  food.database:
    image: postgres:latest
    container_name: food.database
    environment:
      - POSTGRES_DB=food
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
    volumes:
      - ./.containers/food-db:/var/lib/postgresql/data
    ports:
      - 3366:5432
  frontend:
    image: frontend
    build:
      context: ./TestProject.Frontend/TestProject.frontend
      dockerfile: ./dockerfile
    ports:
      - 4200:80

所有服务启动正常,但通过网关URL请求数据时出现如下错误:

requestId: 0HN3GO8DRCRJT:00000002, previousRequestId: No PreviousRequestId, message: 'Error Code: ConnectionToDownstreamServiceError Message: Error connecting to downstream service, exception: System.Net.Http.HttpRequestException: Connection refused (food.api:5010)

       ---> System.Net.Sockets.SocketException (111): Connection refused

         at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)

         at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token)

         at System.Net.Sockets.Socket.<ConnectAsync>g__WaitForConnectWithCancellation|285_0(AwaitableSocketAsyncEventArgs saea, ValueTask connectTask, CancellationToken cancellationToken)

         at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)

         --- End of inner exception stack trace ---

         at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)

         at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)

         at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)

         at System.Net.Http.HttpConnectionPool.AddHttp11ConnectionAsync(QueueItem queueItem)

         at System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellationAsync(CancellationToken cancellationToken)

         at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)

         at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)

         at Ocelot.Requester.TimeoutDelegatingHandler.SendAsync(HttpRequestMessage request, Boolean cancellationToken)

         at Ocelot.Requester.MessageInvokerHttpRequester.GetResponse(HttpContext httpContext) errors found in ResponderMiddleware. Setting error response for request path:/api/recipes, request method: GET'

我最初以为是Ocelot配置问题,但在非Docker环境下调试时网关可正常工作。尝试用localhost:端口替代服务名时,又出现"Cannot assign requested address (localhost:XXXX)"错误。目前无法定位问题原因,恳请有类似经验的开发者提供解决方案。

解决方案

核心问题分析

Docker Compose容器间通信依赖服务名+容器内部端口,而非主机映射端口。你的Ocelot配置中指定的Port: "5010"是主机到容器的映射端口,但容器内API实际监听的是8080,这直接导致网关无法连接下游服务。另外,若服务不在同一Docker网络也会引发连接问题,但你当前的核心问题是端口配置错误。

具体修复步骤

  1. 修正Ocelot配置的下游端口
    将ocelot.json中DownstreamHostAndPorts的端口改为容器内部监听的8080(而非主机映射端口):

    {"Routes": [
        {"DownstreamPathTemplate": "/api/v1/todos/tasks",
         "DownstreamScheme": "http",
         "DownstreamHostAndPorts": [{"Host": "todo.api","Port": "8080"}],
         "UpstreamPathTemplate": "/api/todos",
         "UpstreamHttpMethod": ["Get"]},
        {"DownstreamPathTemplate": "/api/v1/food/recipes",
         "DownstreamScheme": "http",
         "DownstreamHostAndPorts": [{"Host": "food.api","Port": "8080"}],
         "UpstreamPathTemplate": "/api/recipes",
         "UpstreamHttpMethod": ["Get"]}],
     "Aggregates": [],
     "GlobalConfiguration": {"BaseUrl": "http://localhost:5900"}}
    
  2. 确保服务在同一Docker网络
    Docker Compose默认会为项目创建默认网络,所有服务自动加入。若有手动配置网络的情况,需确保gateway.web、todo.api、food.api在同一网络中。显式配置示例:

    version: '3.4'
    
    networks:
      microservices-network:
        driver: bridge
    
    services:
      todo.api:
        # 原有配置
        networks:
          - microservices-network
      food.api:
        # 原有配置
        networks:
          - microservices-network
      gateway.web:
        # 原有配置
        networks:
          - microservices-network
    
  3. 验证容器间DNS解析
    进入网关容器,ping下游服务名确认解析正常:

    docker exec -it gateway.web ping todo.api
    docker exec -it gateway.web ping food.api
    

    若无法ping通,检查服务名是否与docker-compose.yml中services的名称完全一致(Docker服务名不区分大小写,但需避免拼写错误)。

  4. 检查API服务监听地址
    确保API服务在容器内监听0.0.0.0:8080(而非仅localhost),否则容器外部无法访问。可通过以下方式修改:

    • 在.NET API的Program.cs中指定监听地址:
      var app = builder.Build();
      app.Run("http://0.0.0.0:8080");
      
    • 或在Dockerfile中添加环境变量:
      ENV ASPNETCORE_URLS=http://0.0.0.0:8080
      

验证修复

修改配置后,重新构建并启动服务:

docker-compose down
docker-compose build
docker-compose up -d

访问网关URL(如http://localhost:5900/api/recipes),确认可正常获取数据。

内容的提问来源于stack exchange,提问作者John Jameson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 04:32:02