如何在Streamlit部署的Python Web应用中获取用户真实IP地址
解决Streamlit Sharing部署后获取用户真实IP的问题
嘿,我之前在Streamlit Sharing上部署应用时也碰到过一模一样的坑!当时百思不得其解,后来才搞明白为啥会这样:
问题根源
本地测试时,你的代码在自己的设备上运行,调用https://ipapi.co/json/接口时,接口会识别发起请求的设备IP(也就是你的公网IP),所以返回正确结果。但部署到Streamlit Sharing后,你的代码是在Streamlit的云端服务器上执行的——此时调用ipapi接口的是Streamlit的服务器,接口自然会返回服务器的IP,而不是使用应用的用户的真实IP。
解决方案:从请求头提取用户真实IP
Streamlit在新版本中提供了访问用户请求上下文的能力,我们可以通过请求头里的代理字段拿到用户的真实IP(因为Streamlit Sharing用了反向代理,用户的真实IP会被放在特定的请求头中)。具体步骤如下:
- 获取用户真实IP:从请求头的
X-Forwarded-For字段提取,这个字段是反向代理服务器添加的,记录了原始请求的IP地址(如果经过多层代理,会是逗号分隔的多个IP,取第一个即可)。如果这个字段不存在,再 fallback 到X-Real-IP或请求的远程地址。 - 将用户IP传入ipapi接口:不再让接口自动识别IP,而是主动把用户的真实IP拼接到接口URL中,调用
https://ipapi.co/{user_ip}/json/。
完整代码示例
import streamlit as st import requests def get_user_real_ip(): # 获取当前请求的上下文对象(需要Streamlit >=1.21.0) request = st.context.request # 优先从X-Forwarded-For提取真实IP forwarded_for = request.headers.get("X-Forwarded-For") if forwarded_for: # 处理可能的多IP情况(比如经过多层代理),取第一个 user_ip = forwarded_for.split(",")[0].strip() else: # 备选方案:从X-Real-IP或远程地址获取 user_ip = request.headers.get("X-Real-IP", request.remote_addr) return user_ip def fetch_ip_details(user_ip): # 调用ipapi接口,传入用户真实IP api_url = f"https://ipapi.co/{user_ip}/json/" try: response = requests.get(api_url) response.raise_for_status() # 抛出HTTP错误 return response.json() except requests.exceptions.RequestException as e: return {"error": f"无法获取IP信息:{str(e)}"} # 应用主逻辑 st.title("用户IP信息追踪") user_ip = get_user_real_ip() st.success(f"你的真实IP地址:{user_ip}") ip_details = fetch_ip_details(user_ip) if "error" not in ip_details: st.subheader("IP详细信息") st.markdown(f""" - **国家**: {ip_details.get("country_name", "未知")} - **地区**: {ip_details.get("region", "未知")} - **城市**: {ip_details.get("city", "未知")} - **运营商**: {ip_details.get("org", "未知")} """) else: st.error(ip_details["error"])
注意事项
- 确保你的Streamlit版本 >=1.21.0,因为
st.context.request是在这个版本之后引入的。可以在requirements.txt里指定streamlit>=1.21.0。 X-Forwarded-For字段在Streamlit Sharing环境下是可信的,平台会正确传递用户的真实IP,不用担心伪造问题。
内容的提问来源于stack exchange,提问作者SUBHABRATA NATH




