API网关配置Skill api-gateway-configuration

本技能提供API网关的配置指南,包括路由、认证、速率限制和请求/响应转换,适用于微服务架构。关键词包括Kong配置、Nginx配置、AWS API网关、Traefik配置和Node.js网关实现。

微服务 1 次安装 12 次浏览 更新于 3/3/2026

API 网关配置

概览

设计和配置 API 网关以处理微服务架构中的路由、认证、速率限制和请求/响应转换。

何时使用

  • 为微服务设置反向代理
  • 集中 API 认证
  • 实施请求/响应转换
  • 管理后端服务之间的流量
  • 速率限制和配额执行
  • API 版本控制和路由

指南

1. Kong 配置

# kong.yml - Kong 网关配置
_format_version: "2.1"
_transform: true

services:
  - name: user-service
    url: http://user-service:3000
    routes:
      - name: user-routes
        paths:
          - /api/users
          - /api/profile
    plugins:
      - name: rate-limiting
        config:
          minute: 100
          policy: local
      - name: jwt
        config:
          secret: your-secret-key
          key_claim_name: "sub"
      - name: cors
        config:
          origins:
            - "http://localhost:3000"
            - "https://example.com"
          methods:
            - GET
            - POST
            - PUT
            - DELETE
          allow_headers:
            - Content-Type
            - Authorization

  - name: product-service
    url: http://product-service:3001
    routes:
      - name: product-routes
        paths:
          - /api/products
    plugins:
      - name: rate-limiting
        config:
          minute: 500
      - name: request-transformer
        config:
          add:
            headers:
              - "X-Service-Name:product-service"

  - name: order-service
    url: http://order-service:3002
    routes:
      - name: order-routes
        paths:
          - /api/orders
    plugins:
      - name: jwt
      - name: request-size-limiting
        config:
          allowed_payload_size: 5

consumers:
  - username: mobile-app
    custom_id: mobile-app-001
    acls:
      - group: api-users

plugins:
  - name: prometheus
    config:
      latency_metrics: true
      upstream_addr_header: X-Upstream-Addr

2. Nginx 配置

# nginx.conf - API 网关配置
upstream user_service {
    server user-service:3000;
    keepalive 32;
}

upstream product_service {
    server product-service:3001;
    keepalive 32;
}

upstream order_service {
    server order-service:3002;
    keepalive 32;
}

# 速率限制
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
limit_req_zone $http_x_api_key zone=user_limit:10m rate=100r/s;

server {
    listen 80;
    server_name api.example.com;

    # 启用 gzip 压缩
    gzip on;
    gzip_types application/json;
    gzip_min_length 1000;

    # 用户服务路由
    location /api/users {
        limit_req zone=api_limit burst=20 nodelay;

        # 认证检查
        access_by_lua_block {
            local token = ngx.var.http_authorization
            if not token then
                return ngx.HTTP_UNAUTHORIZED
            end
        }

        proxy_pass http://user_service;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # 请求超时
        proxy_connect_timeout 10s;
        proxy_send_timeout 30s;
        proxy_read_timeout 30s;
    }

    # 产品服务路由
    location /api/products {
        limit_req zone=api_limit burst=50 nodelay;

        proxy_pass http://product_service;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # 缓存
        proxy_cache api_cache;
        proxy_cache_valid 200 1m;
        proxy_cache_key "$scheme$request_method$host$request_uri";
    }

    # 订单服务路由(需要认证)
    location /api/orders {
        limit_req zone=user_limit burst=10 nodelay;

        auth_request /auth;
        auth_request_set $auth_user $upstream_http_x_user_id;

        proxy_pass http://order_service;
        proxy_http_version 1.1;
        proxy_set_header X-User-ID $auth_user;
    }

    # 健康检查端点
    location /health {
        access_log off;
        return 200 "healthy
";
        add_header Content-Type text/plain;
    }

    # 指标端点
    location /metrics {
        stub_status on;
        access_log off;
    }
}

# 缓存定义
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=api_cache:10m max_size=1g inactive=60m;

3. AWS API 网关配置

# AWS SAM 模板用于 API 网关
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Resources:
  ApiGateway:
    Type: AWS::Serverless::Api
    Properties:
      StageName: prod
      Auth:
        DefaultAuthorizer: JwtAuthorizer
        Authorizers:
          JwtAuthorizer:
            FunctionArn: !GetAtt AuthorizerFunction.Arn
            Identity:
              Headers:
                - Authorization
      TracingEnabled: true
      MethodSettings:
        - ResourcePath: '/*'
          HttpMethod: '*'
          LoggingLevel: INFO
          DataTraceEnabled: true
          MetricsEnabled: true
          ThrottleSettings:
            BurstLimit: 1000
            RateLimit: 100

  UserServiceFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: nodejs18.x
      Environment:
        Variables:
          USER_SERVICE_URL: !Sub 'https://${UserServiceAlb}.elb.amazonaws.com'
      Events:
        GetUsers:
          Type: Api
          Properties:
            RestApiId: !Ref ApiGateway
            Path: /api/users
            Method: GET
            Auth:
              Authorizer: JwtAuthorizer
        CreateUser:
          Type: Api
          Properties:
            RestApiId: !Ref ApiGateway
            Path: /api/users
            Method: POST
            Auth:
              Authorizer: JwtAuthorizer

  ApiUsagePlan:
    Type: AWS::ApiGateway::UsagePlan
    Properties:
      UsagePlanName: StandardPlan
      ApiStages:
        - ApiId: !Ref ApiGateway
          Stage: prod
      Quota:
        Limit: 10000
        Period: DAY
      Throttle:
        RateLimit: 100
        BurstLimit: 1000

  ApiKey:
    Type: AWS::ApiGateway::ApiKey
    Properties:
      Name: StandardKey
      Enabled: true
      UsagePlanId: !Ref ApiUsagePlan

4. Traefik 配置

# traefik.yml - Traefik API 网关
global:
  checkNewVersion: false
  sendAnonymousUsage: false

entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"

api:
  insecure: true
  dashboard: true

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
  file:
    filename: dynamic.yml

middleware:
  rateLimit:
    rateLimit:
      average: 100
      burst: 50

  authMiddleware:
    basicAuth:
      users:
        - "user:$apr1$r31.....$HqJZimcKQFAMYayBlzkrA/"

routers:
  api-users:
    entrypoints:
      - websecure
    rule: "Path(`/api/users`)"
    service: user-service
    tls:
      certResolver: letsencrypt
    middlewares:
      - rateLimit

  api-products:
    entrypoints:
      - web
    rule: "Path(`/api/products`)"
    service: product-service

services:
  user-service:
    loadBalancer:
      servers:
        - url: "http://user-service:3000"
      healthCheck:
        scheme: http
        path: /health
        interval: 10s
        timeout: 5s

  product-service:
    loadBalancer:
      servers:
        - url: "http://product-service:3001"

5. Node.js 网关实现

const express = require('express');
const httpProxy = require('express-http-proxy');
const rateLimit = require('express-rate-limit');
const jwt = require('jsonwebtoken');

const app = express();

// 速率限制
const limiter = rateLimit({
  windowMs: 60 * 1000,
  max: 100
});

// JWT 验证
const verifyJwt = (req, res, next) => {
  const token = req.headers['authorization']?.split(' ')[1];
  if (!token) return res.status(401).json({ error: 'No token' });

  try {
    jwt.verify(token, process.env.JWT_SECRET);
    next();
  } catch (err) {
    res.status(403).json({ error: 'Invalid token' });
  }
};

// 请求日志
app.use((req, res, next) => {
  console.log(`${new Date().toISOString()} ${req.method} ${req.path}`);
  next();
});

app.use(limiter);

// 用户服务代理
app.use('/api/users', verifyJwt, httpProxy('http://user-service:3000', {
  proxyReqPathResolver: (req) => `/api/users${req.url}`,
  userResDecorator: (proxyRes, proxyResData, userReq, userRes) => {
    proxyRes.headers['X-Gateway'] = 'true';
    return proxyResData;
  }
}));

// 产品服务代理
app.use('/api/products', httpProxy('http://product-service:3001', {
  proxyReqPathResolver: (req) => `/api/products${req.url}`
}));

// 健康检查
app.get('/health', (req, res) => res.json({ status: 'ok' }));

app.listen(8080, () => console.log('Gateway on port 8080'));

最佳实践

✅ DO

  • 在网关级别集中认证
  • 全局实施速率限制
  • 添加全面的日志记录
  • 使用健康检查后端
  • 适当时缓存响应
  • 实施断路器
  • 监控网关指标
  • 生产中使用 HTTPS

❌ DON’T

  • 暴露后端服务细节
  • 跳过请求验证
  • 忘记记录 API 使用情况
  • 使用弱认证
  • 过度缓存动态数据
  • 忽略后端超时
  • 跳过安全头
  • 暴露内部 IP

监控与可观测性

// Prometheus 指标
const promClient = require('prom-client');

const httpRequestDuration = new promClient.Histogram({
  name: 'gateway_http_request_duration_seconds',
  help: 'Duration of HTTP requests in seconds',
  labelNames: ['method', 'route', 'status_code']
});

const httpRequests = new promClient.Counter({
  name: 'gateway_http_requests_total',
  help: 'Total number of HTTP requests',
  labelNames: ['method', 'route', 'status_code']
});

app.use((req, res, next) => {
  const start = Date.now();
  res.on('finish', () => {
    const duration = (Date.now() - start) / 1000;
    httpRequestDuration.labels(req.method, req.path, res.statusCode).observe(duration);
    httpRequests.labels(req.method, req.path, res.statusCode).inc();
  });
  next();
});