
Streamlit 应用中直接执行阻塞式网络请求会导致界面卡死、响应超时,必须结合交互控件与状态管理(如按钮触发 + st.spinner)来实现用户友好的异步体验。
streamlit 应用中直接执行阻塞式网络请求会导致界面卡死、响应超时,必须结合交互控件与状态管理(如按钮触发 + `st.spinner`)来实现用户友好的异步体验。
在 Streamlit 中,脚本顶层代码会在每次用户交互(如刷新、输入、点击)时完整重运行。如果你像传统 Python 脚本一样,在模块顶层直接调用 requests.get(),该请求将在每次重运行时同步执行——而 Streamlit 的默认超时机制和前端渲染逻辑可能导致请求被挂起数分钟,甚至显示空白页,这正是你遇到“10 分钟无输出”的根本原因。相比之下,python app.py 是单次执行,无重运行开销,自然毫秒级完成。
✅ 正确做法是:将 API 调用封装为函数,并仅在明确的用户操作(如点击按钮)后触发,同时配合 st.spinner 提供加载反馈,提升可感知响应性。
以下是一个健壮、可复用的示例:
import streamlit as st
import requests
from typing import Optional, List, Dict
# 配置请求超时(强烈推荐!避免无限等待)
TIMEOUT = 10 # 秒
def fetch_posts() -> Optional[List[Dict]]:
"""安全获取 JSONPlaceholder 帖子列表,含错误处理与超时"""
url = "https://jsonplaceholder.typicode.com/posts"
try:
with st.spinner("正在从服务器获取数据..."):
response = requests.get(url, timeout=TIMEOUT)
response.raise_for_status() # 自动抛出 4xx/5xx 错误
return response.json()
except requests.exceptions.Timeout:
st.error("❌ 请求超时,请检查网络或稍后重试")
except requests.exceptions.ConnectionError:
st.error("❌ 无法连接到服务器,请确认网络状态")
except requests.exceptions.HTTPError as e:
st.error(f"❌ 服务器返回错误:{e}")
except Exception as e:
st.error(f"❌ 未知错误:{e}")
return None
# Streamlit UI 主体
st.title("? Streamlit API 数据获取示例")
st.markdown("_基于 [JSONPlaceholder](https://jsonplaceholder.typicode.com) 免费测试接口_")
if st.button("⬇️ 获取最新 5 篇帖子", use_container_width=True):
data = fetch_posts()
if data:
# 仅展示前 5 条,避免页面过长
st.success(f"✅ 成功获取 {len(data)} 条数据(已显示前 5 条)")
st.json(data[:5])
# 可选:转为 DataFrame 进行表格化展示
# import pandas as pd
# df = pd.DataFrame(data[:5])
# st.dataframe(df[['id', 'title', 'userId']], use_container_width=True)
? 关键注意事项:
-
永远设置
timeout:requests.get(..., timeout=10)是防止挂起的底线; -
避免顶层请求:所有
requests调用必须包裹在函数中,并由st.button/st.selectbox等 widget 显式触发; -
善用状态反馈:
st.spinner,st.success,st.error构成完整的用户体验闭环; -
生产环境建议:对高频请求使用
@st.cache_data(ttl=60)缓存结果(需确保 API 支持缓存),减少重复调用。
通过以上方式,你的 Streamlit 应用将具备响应迅速、容错性强、用户体验清晰的专业级 API 集成能力。











