python(56) : WEB接口获取来源公网IP

from flask import Flask, request
from werkzeug.middleware.proxy_fix import ProxyFix

app = Flask(__name__)

# 修复反向代理下的客户端IP
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_port=1, x_prefix=1)


def get_client_public_ip():
    """获取客户端真实公网IP"""
    if request.remote_addr:
        return request.remote_addr
    x_forwarded_for = request.headers.get('X-Forwarded-For')
    if x_forwarded_for:
        return x_forwarded_for.split(',')[0].strip()
    x_real_ip = request.headers.get('X-Real-IP')
    if x_real_ip:
        return x_real_ip
    return request.remote_addr


@app.route('/')
def index():
    client_ip = get_client_public_ip()
    headers_info = {
        'Remote Address': request.remote_addr,
        'X-Forwarded-For': request.headers.get('X-Forwarded-For', '—'),
        'X-Real-IP': request.headers.get('X-Real-IP', '—'),
        'User-Agent': request.headers.get('User-Agent', '—'),
        'Accept-Language': request.headers.get('Accept-Language', '—'),
        'Protocol': request.scheme.upper(),
    }

    # 构建 HTML 页面(含复制功能)
    html = f"""
    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
        <title>公网IP查询</title>
        <style>
            * {{
                margin: 0;
                padding: 0;
                box-sizing: border-box;
            }}
            body {{
                font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                color: #333;
                line-height: 1.6;
                min-height: 100vh;
                padding: 20px;
            }}
            .container {{
                max-width: 800px;
                margin: 40px auto;
                background: white;
                border-radius: 16px;
                box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
                overflow: hidden;
            }}
            .header {{
                background: #6a20dd;
                color: white;
                padding: 30px;
                text-align: center;
            }}
            .header h1 {{
                font-size: 2.2em;
                margin-bottom: 10px;
            }}
            .header p {{
                font-size: 1.1em;
                opacity: 0.9;
            }}
            .content {{
                padding: 30px;
            }}
            .ip-box {{
                display: flex;
                align-items: center;
                justify-content: space-between;
                margin: 20px 0;
                padding: 20px;
                background: #f7fafc;
                border: 2px dashed #667eea;
                border-radius: 12px;
                font-size: 1.8em;
                color: #4a5568;
                font-weight: bold;
                gap: 15px;
            }}
            .ip-value {{
                flex-grow: 1;
                word-break: break-all;
            }}
            .copy-btn {{
                background: #667eea;
                color: white;
                border: none;
                padding: 10px 18px;
                border-radius: 8px;
                cursor: pointer;
                font-size: 1em;
                transition: background 0.3s;
            }}
            .copy-btn:hover {{
                background: #5a67d8;
            }}
            .copy-success {{
                color: #38a169;
                font-size: 0.9em;
                margin-top: 5px;
                opacity: 0;
                height: 1.2em;
                transition: opacity 0.3s;
            }}
            .show {{
                opacity: 1 !important;
            }}
            .info-table {{
                width: 100%;
                border-collapse: collapse;
                margin-top: 20px;
            }}
            .info-table th {{
                text-align: left;
                padding: 12px 15px;
                background: #f1f5f9;
                color: #2d3748;
                font-weight: 600;
                width: 30%;
            }}
            .info-table td {{
                padding: 12px 15px;
                border-bottom: 1px solid #e2e8f0;
                color: #4a5568;
            }}
            .info-table tr:hover {{
                background-color: #f8f9fc;
            }}
            footer {{
                text-align: center;
                padding: 20px;
                color: #a0aec0;
                font-size: 0.9em;
                background: #f7fafc;
                border-top: 1px solid #e2e8f0;
            }}
        </style>
    </head>
    <body>
        <div class="container">
            <div class="header">
                <h1>🌐 公网 IP 查询</h1>
                <p>查看您的真实公网 IP 地址与请求信息</p>
            </div>
            <div class="content">
                <div class="ip-box">
                    <span class="ip-value" id="ip-value">{client_ip}</span>
                    <button class="copy-btn" onclick="copyIP()">📋 复制</button>
                </div>
                <div class="copy-success" id="copy-success">✅ 复制成功!</div>
                <h2>📝 请求详情</h2>
                <table class="info-table">
                    {''.join(f"<tr><th>{key}</th><td>{value}</td></tr>" for key, value in headers_info.items())}
                </table>
            </div>
            <footer>
                Powered by Flask | 保护您的隐私,仅用于调试与部署
            </footer>
        </div>

        <script>
            function copyIP() {{
                const ipValue = document.getElementById('ip-value').innerText;
                const successMsg = document.getElementById('copy-success');
                const btn = document.querySelector('.copy-btn');

                // 优先使用现代 Clipboard API(仅在安全上下文可用)
                if (navigator.clipboard && window.isSecureContext) {{
                    navigator.clipboard.writeText(ipValue).then(() => {{
                        showSuccess();
                    }}).catch(err => {{
                        console.warn('Clipboard API 失败,尝试降级方案:', err);
                        fallbackCopy(ipValue);
                    }});
                }} else {{
                    // 降级:使用 document.execCommand
                    fallbackCopy(ipValue);
                }}

                function fallbackCopy(text) {{
                    const textarea = document.createElement('textarea');
                    textarea.value = text;
                    textarea.style.position = 'fixed';
                    textarea.style.left = '-999999px';
                    textarea.style.top = '-999999px';
                    document.body.appendChild(textarea);
                    textarea.focus();
                    textarea.select();
                    try {{
                        document.execCommand('copy');
                        showSuccess();
                    }} catch (err) {{
                        console.error('Fallback 复制失败:', err);
                        alert('复制失败,请手动选择复制。');
                    }} finally {{
                        document.body.removeChild(textarea);
                    }}
                }}

                function showSuccess() {{
                    successMsg.classList.add('show');
                    btn.innerText = "✅ 已复制";
                    setTimeout(() => {{
                        successMsg.classList.remove('show');
                        btn.innerText = "📋 复制";
                    }}, 2000);
                }}
            }}
        </script>
    </body>
    </html>
    """
    return html


if __name__ == '__main__':
    print("✅ Flask 服务已启动!")
    print("👉 访问地址: http://127.0.0.1:81")
    print("💡 提示: 在非 HTTPS 或非 localhost 环境下,复制功能将自动降级以确保兼容性。")
    app.run(host='0.0.0.0', port=81, debug=True)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值