微服务架构需要服务之间可靠的通信、外部API请求的保护和负载均衡。代理服务器通过充当服务、外部API和客户端之间的中介来解决这些问题。在本指南中,我们将探讨如何正确地将代理集成到微服务基础设施中,针对不同场景使用哪些类型的代理,以及如何配置安全的通信。
代理在微服务架构中的角色
在微服务架构中,代理服务器执行几项关键功能,这些功能与传统的用于匿名或绕过封锁的代理使用有所不同。在这里,代理成为基础设施不可或缺的一部分,确保系统组件之间的可靠和安全通信。
代理在微服务中的主要角色:
- API网关 — 所有客户端请求的单一入口点,将其路由到相应的微服务,隐藏系统的内部架构
- Sidecar代理 — 与每个服务并行工作的代理容器(服务网格模式),拦截所有传入和传出的流量
- 反向代理 — 在多个同一服务的实例之间分配负载,确保故障恢复
- 正向代理 — 控制和保护对外部API的传出请求,隐藏基础设施的内部IP地址
- 安全代理 — SSL/TLS终止、身份验证、授权、DDoS和其他攻击的保护
代理允许实现重要的架构模式:电路断路器(自动关闭不工作的服务)、重试逻辑(在故障时重试)、速率限制(限制请求频率)、请求/响应转换(数据格式转换)。所有这些使系统对故障更具韧性,并简化了复杂分布式基础设施的管理。
重要: 在微服务架构中,代理在两个层面上工作——作为客户端的外部网关(API网关)和作为服务之间的内部代理(服务网格)。这两个层面对系统的安全性和可靠性至关重要。
不同使用场景的代理类型
选择代理类型取决于微服务架构中的具体任务。不同的场景需要不同的特性:速度、可靠性、匿名性或地理分布。
| 场景 | 代理类型 | 原因 |
|---|---|---|
| 服务间内部通信 | HTTP/HTTPS代理(Envoy,NGINX) | 最大速度,低延迟,支持HTTP/2 |
| 对外部API的请求有限制 | 住宅代理 | 绕过速率限制,真实用户IP,低封锁风险 |
| 数据解析用于分析 | 数据中心代理 | 高速,低成本,适合大规模请求 |
| 与移动API的交互 | 移动代理 | 模拟真实移动用户,访问仅限移动的API |
| 负载均衡 | 反向代理(HAProxy,NGINX) | 流量分配,健康检查,故障时自动切换 |
| 地理分布的系统 | 带地理定位的住宅代理 | 访问区域API,符合数据本地化要求 |
对于微服务之间的内部通信,通常使用专门的代理解决方案,如Envoy Proxy或NGINX,这些解决方案经过优化以实现低延迟和高吞吐量。它们支持现代协议(HTTP/2,gRPC)并与服务网格系统集成。
对于与外部API的交互,选择取决于特定服务的要求。如果API有严格的速率限制或阻止来自数据中心IP的请求,则需要住宅代理。对于大规模数据收集,速度比匿名性更重要,数据中心代理是合适的选择。在处理检查设备类型或需要移动IP地址的API时,移动代理是必需的。
代理作为API网关:保护和路由
API网关是一个专用的代理服务器,充当所有客户端请求到微服务系统的单一入口点。客户不直接访问数十个不同的服务,而是将所有请求发送到一个API网关地址,后者将其路由到所需的服务。
API网关的主要功能:
- 请求路由 — 根据URL、头部或其他参数确定哪个微服务应处理请求
- 身份验证和授权 — 验证令牌(JWT,OAuth),管理对不同服务的访问
- 速率限制 — 限制来自单个客户端的请求数量,以防止过载和DDoS
- 响应聚合 — 将来自多个服务的数据合并为一个响应返回给客户端
- 协议转换 — 将REST转换为gRPC,将HTTP/1.1转换为HTTP/2
- 缓存 — 保存常请求的数据以减少对服务的负载
- 日志记录和监控 — 集中收集所有请求的指标和日志
常用的API网关解决方案有:Kong,Tyk,AWS API Gateway,Azure API Management,NGINX Plus,Traefik。选择取决于系统的规模、性能要求和使用的云平台。
// NGINX作为API网关的配置示例
upstream auth_service {
server auth:8001;
}
upstream user_service {
server user:8002;
}
upstream order_service {
server order:8003;
}
server {
listen 80;
server_name api.example.com;
# 请求频率限制
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
location /api/auth/ {
limit_req zone=api_limit burst=20;
proxy_pass http://auth_service/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /api/users/ {
# 在代理之前检查令牌
auth_request /auth/verify;
proxy_pass http://user_service/;
}
location /api/orders/ {
auth_request /auth/verify;
proxy_pass http://order_service/;
}
# 内部端点用于验证令牌
location = /auth/verify {
internal;
proxy_pass http://auth_service/verify;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
}
}
API网关隐藏了系统的内部架构,外部客户无法知道有多少微服务存在以及它们如何交互——他们只看到一个统一的API。这简化了版本管理,使得可以在不影响客户的情况下更改内部结构,并提高了安全性,因为内部服务不直接从互联网访问。
与服务网格的集成(Istio,Linkerd)
服务网格是一个基础设施层,通过在每个服务旁边部署的代理服务器管理微服务之间的通信(Sidecar模式)。与仅处理外部流量的API网关不同,服务网格控制服务之间的所有内部流量。
最流行的服务网格解决方案是Istio(使用Envoy Proxy作为sidecar)和Linkerd(使用自有的轻量级代理)。它们会自动在Kubernetes中的每个pod旁边注入代理容器,拦截所有传入和传出的流量。
通过代理的服务网格功能:
- 互相TLS(mTLS) — 自动加密服务之间的所有流量,并进行相互身份验证
- 流量管理 — 路由管理、金丝雀发布、A/B测试
- 可观察性 — 自动收集指标、追踪和日志,无需更改服务代码
- 韧性 — 电路断路器、重试逻辑、超时管理、故障注入测试
- 服务发现 — 自动发现服务和负载均衡
# Istio VirtualService的路由配置示例
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: user-service
spec:
hosts:
- user-service
http:
- match:
- headers:
version:
exact: "v2"
route:
- destination:
host: user-service
subset: v2
- route:
- destination:
host: user-service
subset: v1
weight: 90
- destination:
host: user-service
subset: v2
weight: 10 # 金丝雀发布:10%的流量到v2
---
# 电路断路器以防止级联故障
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: user-service
spec:
host: user-service
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
http:
http1MaxPendingRequests: 50
maxRequestsPerConnection: 2
outlierDetection:
consecutiveErrors: 5
interval: 30s
baseEjectionTime: 30s
maxEjectionPercent: 50
服务网格解决了“分布式单体”的问题——服务之间的交互逻辑(重试、超时、电路断路器)在每个服务的代码中重复。相反,所有这些逻辑都被移到代理层,从而简化了服务的代码,并确保整个系统的一致性行为。
一个重要的优势是流量的完全透明性。服务之间的每个请求都经过代理,代理记录指标:响应时间、错误代码、有效负载大小。这些数据自动发送到监控系统(Prometheus,Grafana)和追踪系统(Jaeger,Zipkin),在不需要在每个服务的代码中添加工具的情况下,创建分布式系统的完整工作图景。
通过代理保护对外部API的请求
微服务经常与外部API进行交互:支付系统、地理定位服务、社交媒体API、数据提供商。直接请求外部API会产生几个问题:暴露基础设施的内部IP地址、在超过速率限制时被封锁的风险、对传出流量缺乏控制。
使用代理进行传出请求可以解决这些问题并添加额外的功能:
- 隐藏基础设施 — 外部API看到的是代理的IP地址,而不是您的服务器
- 绕过速率限制 — IP地址轮换以分散请求
- 地理分布 — 通过位于所需国家的代理访问区域API
- 集中管理 — 所有传出请求的单一控制点
- 响应缓存 — 减少对昂贵API的请求数量
- 监控和日志记录 — 跟踪所有对外部服务的调用
// Python:为外部API的请求配置代理
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
class ExternalAPIClient:
def __init__(self, proxy_url, proxy_rotation=False):
self.session = requests.Session()
# 配置代理
self.proxies = {
'http': proxy_url,
'https': proxy_url
}
# 重试逻辑以提高韧性
retry_strategy = Retry(
total=3,
backoff_factor=1,
status_forcelist=[429, 500, 502, 503, 504],
allowed_methods=["GET", "POST"]
)
adapter = HTTPAdapter(max_retries=retry_strategy)
self.session.mount("http://", adapter)
self.session.mount("https://", adapter)
def call_payment_api(self, data):
"""通过代理请求支付API"""
try:
response = self.session.post(
'https://api.payment-provider.com/charge',
json=data,
proxies=self.proxies,
timeout=10,
headers={'User-Agent': 'MyService/1.0'}
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
# 记录错误
print(f"支付API错误: {e}")
raise
# 使用代理池进行轮换
class ProxyPool:
def __init__(self, proxy_list):
self.proxies = proxy_list
self.current = 0
def get_next(self):
proxy = self.proxies[self.current]
self.current = (self.current + 1) % len(self.proxies)
return proxy
# 初始化
proxy_pool = ProxyPool([
'http://user:pass@proxy1.example.com:8080',
'http://user:pass@proxy2.example.com:8080',
'http://user:pass@proxy3.example.com:8080'
])
# 对于每个请求使用下一个代理
client = ExternalAPIClient(proxy_pool.get_next())
对于具有严格限制或阻止来自数据中心IP请求的外部API,住宅代理变得必不可少。它们提供真实家庭用户的IP地址,从而降低了被封锁的风险,并允许绕过地理限制。
// Node.js:为外部API配置自动轮换的代理
const axios = require('axios');
const HttpsProxyAgent = require('https-proxy-agent');
class ExternalAPIService {
constructor(proxyList) {
this.proxyList = proxyList;
this.currentProxyIndex = 0;
this.requestCounts = new Map(); // 请求计数器用于速率限制
}
getNextProxy() {
const proxy = this.proxyList[this.currentProxyIndex];
this.currentProxyIndex = (this.currentProxyIndex + 1) % this.proxyList.length;
return proxy;
}
async callAPI(endpoint, data, options = {}) {
const proxyUrl = this.getNextProxy();
const agent = new HttpsProxyAgent(proxyUrl);
// 速率限制:每个代理每分钟最多100个请求
const proxyKey = proxyUrl;
const now = Date.now();
const count = this.requestCounts.get(proxyKey) || { count: 0, resetTime: now + 60000 };
if (count.count >= 100 && now < count.resetTime) {
// 切换到下一个代理
return this.callAPI(endpoint, data, options);
}
try {
const response = await axios({
method: options.method || 'POST',
url: endpoint,
data: data,
httpsAgent: agent,
timeout: options.timeout || 10000,
headers: {
'User-Agent': 'Mozilla/5.0 (compatible; MyService/1.0)',
...options.headers
}
});
// 更新计数器
if (now >= count.resetTime) {
this.requestCounts.set(proxyKey, { count: 1, resetTime: now + 60000 });
} else {
count.count++;
}
return response.data;
} catch (error) {
if (error.response?.status === 429) {
// 超过速率限制 - 切换到其他代理
console.log(`在${proxyUrl}上超出速率限制,切换代理`);
return this.callAPI(endpoint, data, options);
}
throw error;
}
}
}
// 使用
const apiService = new ExternalAPIService([
'http://user:pass@proxy1.example.com:8080',
'http://user:pass@proxy2.example.com:8080'
]);
module.exports = apiService;
负载均衡和故障恢复
代理服务器在通过负载均衡和故障时自动切换来确保微服务系统的高可用性方面发挥着关键作用。当您运行多个同一服务的实例(以进行水平扩展)时,代理会在它们之间分配请求,以确保负载均匀。
主要的负载均衡算法:
- 轮询 — 按顺序将请求发送到列表中的每个服务器,简单且有效,适用于同质服务器
- 最少连接 — 将请求发送到活动连接最少的服务器,适合长时间请求
- IP哈希 — 根据客户端的IP将其绑定到特定服务器,确保粘性会话
- 加权轮询 — 根据服务器的能力分配(更强大的服务器接收更多请求)
- 随机 — 随机选择服务器,适合无状态服务
# HAProxy配置用于负载均衡和健康检查
global
maxconn 4096
log stdout format raw local0
defaults
mode http
timeout connect 5s
timeout client 50s
timeout server 50s
option httplog
frontend api_frontend
bind *:80
default_backend api_servers
backend api_servers
balance roundrobin
# 健康检查:每2秒检查一次/health
option httpchk GET /health
http-check expect status 200
# 重试逻辑
retries 3
option redispatch
# 带权重的服务器(server3的能力是其他服务器的两倍)
server server1 10.0.1.10:8080 check weight 1 maxconn 500
server server2 10.0.1.11:8080 check weight 1 maxconn 500
server server3 10.0.1.12:8080 check weight 2 maxconn 1000
# 备用服务器(仅在主要服务器不可用时使用)
server backup1 10.0.2.10:8080 check backup
健康检查是确保故障恢复的关键功能。代理定期检查每个服务器的可用性(通常通过HTTP端点/health或/ready),并自动将不工作的服务器排除在负载均衡池之外。当服务器恢复并开始响应健康检查时,它会自动返回到池中。
通过代理的故障恢复策略:
- 主动健康检查 — 代理主动询问服务器以检查其可用性
- 被动健康检查 — 代理跟踪实际请求,并在错误累积时排除服务器
- 电路断路器 — 暂时关闭有问题的服务以防止级联故障
- 优雅降级 — 在故障时切换到简化模式或缓存数据
- 切换到备用 — 自动切换到备用服务器或区域
// Python:为外部服务的代理实现电路断路器
from datetime import datetime, timedelta
from enum import Enum
class CircuitState(Enum):
CLOSED = "closed" # 正常工作
OPEN = "open" # 服务不可用,请求被阻止
HALF_OPEN = "half_open" # 恢复后的测试模式
class CircuitBreaker:
def __init__(self, failure_threshold=5, timeout=60, success_threshold=2):
self.failure_threshold = failure_threshold # 打开前的错误数
self.timeout = timeout # 尝试恢复的秒数
self.success_threshold = success_threshold # 关闭的成功次数
self.state = CircuitState.CLOSED
self.failures = 0
self.successes = 0
self.last_failure_time = None
def call(self, func, *args, **kwargs):
if self.state == CircuitState.OPEN:
if datetime.now() - self.last_failure_time > timedelta(seconds=self.timeout):
self.state = CircuitState.HALF_OPEN
print("电路断路器:转入HALF_OPEN")
else:
raise Exception("电路断路器OPEN:服务不可用")
try:
result = func(*args, **kwargs)
self._on_success()
return result
except Exception as e:
self._on_failure()
raise e
def _on_success(self):
self.failures = 0
if self.state == CircuitState.HALF_OPEN:
self.successes += 1
if self.successes >= self.success_threshold:
self.state = CircuitState.CLOSED
self.successes = 0
print("电路断路器:恢复,转入CLOSED")
def _on_failure(self):
self.failures += 1
self.last_failure_time = datetime.now()
if self.failures >= self.failure_threshold:
self.state = CircuitState.OPEN
print(f"电路断路器OPEN:{self.failures}个连续错误")
# 使用
breaker = CircuitBreaker(failure_threshold=3, timeout=30)
def call_external_service():
# 您的代码通过代理请求外部API
pass
try:
result = breaker.call(call_external_service)
except Exception as e:
# 回退逻辑:缓存、默认值等
print(f"服务不可用:{e}")
服务间通信的安全性
在微服务架构中,代理服务器提供多个安全级别:流量加密、服务身份验证、攻击保护和网络段隔离。如果没有正确的安全配置,服务间的内部流量可能会被拦截或伪造。
通过代理的安全关键点:
- 互相TLS(mTLS) — 双向身份验证,客户端和服务器都验证对方的证书。服务网格自动在所有服务之间配置mTLS
- TLS终止 — 代理在边界解密HTTPS流量,验证后通过安全通道传递给服务
- JWT验证 — 在请求到达服务之前在代理级别验证访问令牌
- IP白名单 — 仅允许来自授权IP地址的访问
- DDoS保护 — 速率限制、连接限制、在代理级别的SYN洪水保护
- WAF(Web应用防火墙) — 过滤恶意请求,防止SQL注入、XSS
# NGINX配置与SSL/TLS和安全性
server {
listen 443 ssl http2;
server_name api.internal.example.com;
# SSL证书
ssl_certificate /etc/nginx/certs/api.crt;
ssl_certificate_key /etc/nginx/certs/api.key;
# 现代协议和密码
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# 客户端证书用于mTLS
ssl_client_certificate /etc/nginx/certs/ca.crt;
ssl_verify_client on;
# 安全头部
add_header Strict-Transport-Security "max-age=31536000" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
# 速率限制
limit_req_zone $binary_remote_addr zone=api:10m rate=100r/s;
limit_req zone=api burst=200 nodelay;
# 连接限制
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_conn addr 10;
# IP白名单
allow 10.0.0.0/8; # 内部网络
allow 172.16.0.0/12; # VPC
deny all;
location / {
# JWT令牌检查
auth_jwt "受限API";
auth_jwt_key_file /etc/nginx/jwt_key.json;
proxy_pass http://backend_service;
# 传递客户端证书信息
proxy_set_header X-Client-DN $ssl_client_s_dn;
proxy_set_header X-Client-Verify $ssl_client_verify;
}
}
服务网格大大简化了安全配置,自动生成和轮换mTLS证书,应用访问策略并加密服务之间的所有流量。例如,在Istio中,可以指定“payment”服务只能接受来自“order”服务的请求,这将在代理级别自动应用,而无需更改服务代码。
生产环境的重要性: 始终在服务之间的内部通信中使用mTLS,即使它们位于同一私有网络中。这可以防止中间人攻击,并确保服务级别的身份验证,而不仅仅是在网络级别。
代理流量的监控和日志记录
代理服务器提供了集中监控微服务系统中所有流量的独特机会。由于所有流量都通过代理(无论是通过API网关的外部流量,还是通过服务网格的内部流量),您可以在不需要为每个服务添加工具的情况下获得系统的完整可见性。
代理级别监控的关键指标:
- 延迟 — 每个阶段处理请求的时间:代理、服务、外部API
- 吞吐量 — 每秒请求数量、传输数据量
- 错误率 — 错误的百分比(4xx,5xx),错误类型,问题端点
- 连接指标 — 活动连接数量,连接池使用情况
- 电路断路器状态 — 每个服务的电路断路器状态
- SSL/TLS指标 — 证书状态,协议版本,握手错误
# NGINX配置用于将指标导出到Prometheus
server {
listen 9113;
location /metrics {
stub_status;
access_log off;
allow 10.0.0.0/8; # 仅限Prometheus服务器
deny all;
}
}
# 以JSON格式记录以进行结构化日志记录
log_format json_combined escape=json
'{'
'"time_local":"$time_local",'
'"remote_addr":"$remote_addr",'
'"request":"$request",'
'"status": "$status",'
'"body_bytes_sent":"$body_bytes_sent",'
'"request_time":"$request_time",'
'"upstream_response_time":"$upstream_response_time",'
'"upstream_addr":"$upstream_addr",'
'"http_referrer":"$http_referer",'
'"http_user_agent":"$http_user_agent",'
'"http_x_forwarded_for":"$http_x_forwarded_for"'
'}';
access_log /var/log/nginx/access.log json_combined;
分布式追踪是通过代理进行监控的最强大功能之一。每个请求获得一个唯一的追踪ID,代理将其添加到头部并传递给服务链。追踪系统(Jaeger,Zipkin)收集来自所有代理的信息,并构建请求在系统中的完整路径,显示它在每个服务中花费的时间。
// Node.js:在代理中间件中添加追踪功能
const express = require('express');
const { v4: uuidv4 } = require('uuid');
const axios = require('axios');
const app = express();
// 中间件用于添加追踪ID
app.use((req, res, next) => {
// 从头部获取追踪ID或创建新的
const traceId = req.headers['x-trace-id'] || uuidv4();
const spanId = uuidv4();
// 添加到头部以便传递
req.traceId = traceId;
req.spanId = spanId;
res.setHeader('x-trace-id', traceId);
// 记录处理开始时间
const startTime = Date.now();
res.on('finish', () => {
const duration = Date.now() - startTime;
// 结构化日志以供分析
console.log(JSON.stringify({
timestamp: new Date().toISOString(),
traceId: traceId,
spanId: spanId,
method: req.method,
path: req.path,
status: res.statusCode,
duration: duration,
userAgent: req.headers['user-agent'],
ip: req.ip
}));
});
next();
});
// 代理端点,传递追踪头部
app.all('/api/*', async (req, res) => {
const targetService = determineTargetService(req.path);
try {
const response = await axios({
method: req.method,
url: `http://${targetService}${req.path}`,
data: req.body,
headers: {
...req.headers,
'x-trace-id': req.traceId,
'x-parent-span-id': req.spanId,
'x-span-id': uuidv4() // 下游请求的新span
}
});
res.status(response.status).json(response.data);
} catch (error) {
console.error(JSON.stringify({
traceId: req.traceId,
error: error.message,
service: targetService
}));
res.status(500).json({ error: '服务不可用' });
}
});
function determineTargetService(path) {
if (path.startsWith('/api/users')) return 'user-service:8080';
if (path.startsWith('/api/orders')) return 'order-service:8080';
return 'default-service:8080';
}
app.listen(3000);
基于代理指标的警报可以快速发现问题。例如,可以设置警报以监控:延迟的突然增长(可能是某个服务在降级)、错误率超过阈值(代码或依赖问题)、流量模式的变化(可能的DDoS攻击或病毒负载)。
Python和Node.js的实现示例
让我们来看一些在Python和Node.js中将代理集成到微服务中的实际示例,适用于不同场景:内部通信、与外部API的交互、负载均衡。
Python:带有外部API代理的服务
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import httpx
import asyncio
from typing import List, Optional
import logging
app = FastAPI()
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class ProxyConfig(BaseModel):
url: str
max_requests_per_minute: int = 60
class ProxyPool:
def __init__(self, proxies: List[ProxyConfig]):
self.proxies = proxies
self.current_index = 0
self.request_counts = {p.url: 0 for p in proxies}
self.reset_time = asyncio.get_event_loop().time() + 60
async def get_next_proxy(self) -> str:
# 每分钟重置计数器
current_time = asyncio.get_event_loop().time()
if current_time >= self.reset_time:
self.request_counts = {p.url: 0 for p in self.proxies}
self.reset_time = current_time + 60
# 找到可用请求的代理
for _ in range(len(self.proxies)):
proxy = self.proxies[self.current_index]
self.current_index = (self.current_index + 1) % len(self.proxies)
if self.request_counts[proxy.url] < proxy.max_requests_per_minute:
self.request_counts[proxy.url] += 1
return proxy.url
# 所有代理都已达到限制
raise HTTPException(status_code=429, detail="所有代理都已达到速率限制")
# 初始化代理池
proxy_pool = ProxyPool([
ProxyConfig(url="http://user:pass@proxy1.example.com:8080", max_requests_per_minute=100),
ProxyConfig(url="http://user:pass@proxy2.example.com:8080", max_requests_per_minute=100),
ProxyConfig(url="http://user:pass@proxy3.example.com:8080", max_requests_per_minute=100)
])
class ExternalAPIClient:
def __init__(self, proxy_pool: ProxyPool):
self.proxy_pool = proxy_pool
async def fetch_data(self, endpoint: str, params: dict = None) -> dict:
proxy_url = await self.proxy_pool.get_next_proxy()
async with httpx.AsyncClient(proxies={"http://": proxy_url, "https://": proxy_url}) as client:
try:
response = await client.get(
endpoint,
params=params,
timeout=10.0,
headers={"User-Agent": "MyMicroservice/1.0"}
)
response.raise_for_status()
logger.info(f"成功通过{proxy_url}从{endpoint}获取数据")
return response.json()
except httpx.HTTPStatusError as e:
logger.error(f"来自{endpoint}的HTTP错误 {e.response.status_code}")
raise HTTPException(status_code=e.response.status_code, detail=str(e))
except httpx.RequestError as e:
logger.error(f"请求{endpoint}时出错: {e}")
raise HTTPException(status_code=503, detail="外部API不可用")
api_client = ExternalAPIClient(proxy_pool)
@app.get("/data/{resource_id}")
async def get_external_data(resource_id: str):
"""通过代理从外部API获取数据的端点"""
external_endpoint = f"https://api.external-service.com/v1/resources/{resource_id}"
try:
data = await api_client.fetch_data(external_endpoint)
return {"status": "success", "data": data}
except HTTPException:
raise
except Exception as e:
logger.error(f"意外错误: {e}")
raise HTTPException(status_code=500, detail="内部服务器错误")
@app.get("/health")
async def health_check():
return {"status": "healthy", "service": "external-api-proxy"}
# 启动:uvicorn main:app --host 0.0.0.0 --port 8000
Node.js:带有负载均衡的API网关
const express = require('express');
const axios = require('axios');
const rateLimit = require('express-rate-limit');
const app = express();
app.use(express.json());
// 微服务配置
const services = {
users: [
{ url: 'http://user-service-1:8001', healthy: true, activeConnections: 0 },
{ url: 'http://user-service-2:8001', healthy: true, activeConnections: 0 },
// 其他服务...
],
// 其他微服务...
};
// 负载均衡中间件
app.use((req, res, next) => {
const service = services.users.find(s => s.healthy);
if (!service) {
return res.status(503).send('所有用户服务不可用');
}
// 选择服务并增加活动连接数
service.activeConnections++;
// 代理请求
axios({
method: req.method,
url: `${service.url}${req.path}`,
data: req.body,
headers: req.headers
})
.then(response => {
res.status(response.status).send(response.data);
})
.catch(error => {
res.status(error.response?.status || 500).send(error.message);
})
.finally(() => {
// 减少活动连接数
service.activeConnections--;
});
});
// 启动服务
app.listen(3000, () => {
console.log('API网关正在监听3000端口');
});