☕ NEW! 完成新手任務即可參加抽獎!LINE 星巴克禮券等你拿,名額有限!        🎉 推廣活動:邀請好友註冊 DevLearn,累積推薦抽 LINE 星巴克禮券! 活動詳情 →        🔥 活動期間 2026/4/1 - 5/31 |已有 0 人參加       
microservices 中級

🚪 API Gateway:Ocelot 與 YARP

📌 為什麼需要 API Gateway?

沒有 Gateway 時,前端需要知道每個微服務的位址:

前端直接呼叫多個微服務(❌ 不好的做法):
├── http://user-service:5001/api/users
├── http://product-service:5002/api/products
├── http://order-service:5003/api/orders
└── http://payment-service:5004/api/payments

有 Gateway 後,前端只需要知道一個位址:

前端只呼叫 Gateway(✅ 推薦做法):
└── http://api-gateway:5000/api/...
    ├── /api/users    → 轉發到 user-service
    ├── /api/products → 轉發到 product-service
    ├── /api/orders   → 轉發到 order-service
    └── /api/payments → 轉發到 payment-service

API Gateway 的功能

功能 說明
路由 根據 URL 轉發到對應的微服務
負載平衡 將請求分散到多個服務實例
認證授權 統一在 Gateway 驗證 JWT Token
速率限制 防止 API 被濫用
快取 快取常用的回應
聚合 合併多個服務的回應為一個
日誌 集中記錄所有 API 請求

📌 Ocelot 設定與路由

安裝與設定

dotnet new webapi -n ApiGateway
cd ApiGateway
dotnet add package Ocelot
// Program.cs
var builder = WebApplication.CreateBuilder(args);

builder.Configuration.AddJsonFile("ocelot.json", optional: false, reloadOnChange: true);
builder.Services.AddOcelot();

var app = builder.Build();
await app.UseOcelot();
app.Run();

ocelot.json 路由設定

{
  "Routes": [
    {
      "DownstreamPathTemplate": "/api/products/{everything}",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        { "Host": "product-service", "Port": 5002 }
      ],
      "UpstreamPathTemplate": "/api/products/{everything}",
      "UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ]
    },
    {
      "DownstreamPathTemplate": "/api/orders/{everything}",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        { "Host": "order-service", "Port": 5003 }
      ],
      "UpstreamPathTemplate": "/api/orders/{everything}",
      "UpstreamHttpMethod": [ "GET", "POST" ],
      "AuthenticationOptions": {
        "AuthenticationProviderKey": "Bearer"
      }
    }
  ],
  "GlobalConfiguration": {
    "BaseUrl": "http://localhost:5000"
  }
}

📌 YARP — 微軟官方反向代理

YARP(Yet Another Reverse Proxy)是微軟官方的高效能反向代理,比 Ocelot 更適合大規模生產環境。

安裝

dotnet add package Yarp.ReverseProxy

設定 YARP

// Program.cs
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddReverseProxy()
    .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));

var app = builder.Build();
app.MapReverseProxy();
app.Run();

appsettings.json 設定

{
  "ReverseProxy": {
    "Routes": {
      "product-route": {
        "ClusterId": "product-cluster",
        "Match": {
          "Path": "/api/products/{**catch-all}"
        },
        "Transforms": [
          { "PathPattern": "/api/products/{**catch-all}" }
        ]
      },
      "order-route": {
        "ClusterId": "order-cluster",
        "Match": {
          "Path": "/api/orders/{**catch-all}"
        }
      }
    },
    "Clusters": {
      "product-cluster": {
        "LoadBalancingPolicy": "RoundRobin",
        "Destinations": {
          "product-1": { "Address": "http://product-service-1:5002" },
          "product-2": { "Address": "http://product-service-2:5002" }
        }
      },
      "order-cluster": {
        "Destinations": {
          "order-1": { "Address": "http://order-service:5003" }
        }
      }
    }
  }
}

📌 Ocelot vs YARP 比較

功能 Ocelot YARP
維護者 社群 微軟官方
效能
設定方式 JSON 檔案 JSON / 程式碼
負載平衡 內建 內建(更多策略)
熱更新設定 支援 支援
自訂中介軟體 有限 靈活
適用場景 中小型專案 大型生產環境

📌 負載平衡與速率限制

YARP 負載平衡策略

// 支援的負載平衡策略
builder.Services.AddReverseProxy()
    .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));

// 可用的策略:
// - RoundRobin:輪流分配
// - Random:隨機
// - LeastRequests:最少請求
// - PowerOfTwoChoices:隨機選兩個,選負載低的
// - FirstAlphabetical:按字母順序(測試用)

速率限制

// 使用 ASP.NET Core 內建的速率限制
builder.Services.AddRateLimiter(options =>
{
    options.AddFixedWindowLimiter("fixed", opt =>
    {
        opt.PermitLimit = 100;           // 每個窗口 100 個請求
        opt.Window = TimeSpan.FromMinutes(1);
        opt.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
        opt.QueueLimit = 10;
    });

    options.AddSlidingWindowLimiter("sliding", opt =>
    {
        opt.PermitLimit = 60;
        opt.Window = TimeSpan.FromMinutes(1);
        opt.SegmentsPerWindow = 6;       // 每 10 秒一個段落
    });
});

app.UseRateLimiter();

📌 認證與授權在 Gateway 層

// Program.cs — API Gateway
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.Authority = "http://identity-service";
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateAudience = false
        };
    });

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("AdminOnly", policy =>
        policy.RequireRole("admin"));
});

// 在 YARP 路由中套用授權
// appsettings.json 中設定 AuthorizationPolicy

📌 範例:聚合多個服務的回應

// 自訂聚合端點:一次呼叫取得訂單 + 產品 + 用戶資訊
app.MapGet("/api/aggregation/order-details/{orderId}",
    async (Guid orderId, IHttpClientFactory factory) =>
{
    var orderClient = factory.CreateClient("OrderService");
    var productClient = factory.CreateClient("ProductService");
    var userClient = factory.CreateClient("UserService");

    // 平行呼叫三個服務
    var orderTask = orderClient.GetFromJsonAsync<OrderDto>(
        $"/api/orders/{orderId}");
    var order = await orderTask;
    if (order is null) return Results.NotFound();

    var userTask = userClient.GetFromJsonAsync<UserDto>(
        $"/api/users/{order.CustomerId}");
    var productTasks = order.Items.Select(item =>
        productClient.GetFromJsonAsync<ProductDto>(
            $"/api/products/{item.ProductId}"));

    await Task.WhenAll(userTask, Task.WhenAll(productTasks));

    return Results.Ok(new
    {
        Order = order,
        Customer = userTask.Result,
        Products = productTasks.Select(t => t.Result)
    });
});

下一章: 我們將學習如何用 Docker 容器化微服務。

💡 大家的想法 · 0

載入中...
💬 即時聊天室 🟢 0 人在線
😀 😎 🤓 💻 🎮 🎸 🔥
➕ 新問題
📋 我的工單
💬 LINE 社群
🔒
需要註冊才能使用此功能
註冊帳號即可解鎖測驗、遊戲、簽到、筆記下載等所有功能,完全免費!
免費註冊