FastAPI经CloudFlare代理后如何获取真实客户端IP?
解决方案
方案1:自定义日志过滤器,直接读取CloudFlare专属请求头
如果仅需日志记录真实IP,无需修改Request对象的client属性,可直接在日志配置中指定读取CF-Connecting-IP或X-Original-Forwarded-For字段。
代码示例
import logging from fastapi import Request class RealIPFilter(logging.Filter): def filter(self, record): if hasattr(record, 'request'): request: Request = record.request # 优先取CF-Connecting-IP,没有则 fallback到X-Original-Forwarded-For real_ip = request.headers.get('CF-Connecting-IP') or request.headers.get('X-Original-Forwarded-For') if real_ip: record.client_ip = real_ip else: record.client_ip = request.client.host if request.client else 'unknown' return True # 配置日志处理器与格式 logger = logging.getLogger('uvicorn.access') logger.addFilter(RealIPFilter()) handler = logging.StreamHandler() handler.setFormatter(logging.Formatter('%(client_ip)s - "%(request_line)s" %(status_code)s')) logger.addHandler(handler)
方案2:通过中间件修改Request的scope获取真实IP
FastAPI基于Starlette框架,Request的client属性来源于scope['client']字典,该字典可修改。通过中间件替换scope['client']的值,即可让request.client.host返回真实客户端IP。
代码示例
from fastapi import FastAPI, Request from starlette.middleware.base import BaseHTTPMiddleware app = FastAPI() class RealIPMiddleware(BaseHTTPMiddleware): async def dispatch(self, request: Request, call_next): real_ip = request.headers.get('CF-Connecting-IP') or request.headers.get('X-Original-Forwarded-For') if real_ip: # 处理IP带端口的情况,无端口则默认设为0 ip_port = real_ip.split(':') real_ip_tuple = (ip_port[0], int(ip_port[1])) if len(ip_port) == 2 else (real_ip, 0) # 修改scope中的client值 request.scope['client'] = real_ip_tuple response = await call_next(request) return response # 注册中间件 app.add_middleware(RealIPMiddleware)
方案3:修正Ingress Nginx配置,转发真实IP到FastAPI
若之前修改Ingress配置未生效,可通过添加正确的annotations,让Nginx将CloudFlare传递的真实IP写入X-Real-IP或X-Forwarded-For,配合FastAPI已有的proxy_headers=True配置即可生效。
Ingress YAML配置示例
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: your-ingress-name annotations: # 指定从CF-Connecting-IP获取真实IP nginx.ingress.kubernetes.io/real-ip-header: "CF-Connecting-IP" # 仅信任CloudFlare官方IP段,防止伪造请求头 nginx.ingress.kubernetes.io/proxy-real-ip-cidr: "103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,104.16.0.0/13,104.24.0.0/14,108.162.192.0/18,131.0.72.0/22,141.101.64.0/18,162.158.0.0/15,172.64.0.0/13,173.245.48.0/20,188.114.96.0/20,190.93.240.0/20,197.234.240.0/22,198.41.128.0/17" # 配置转发头字段 nginx.ingress.kubernetes.io/forwarded-for-header: "X-Forwarded-For" spec: tls: - hosts: - your-domain.com secretName: your-tls-secret rules: - host: your-domain.com http: paths: - path: / pathType: Prefix backend: service: name: your-service-name port: number: 8443
内容的提问来源于stack exchange,提问作者mpp9009
相关产品推荐
相关产品推荐

