React SPA+Django后端:如何将客户端API调用改为服务端调用
看起来你想把原本在React客户端通过fetch获取API数据的逻辑,转移到服务端来完成——这样可以避免客户端跨域问题(虽然你现在是本地,但生产环境可能会有),还能实现数据预渲染,提升首屏加载速度。下面给你两种最常用的实现方案,根据你的项目情况选就行:
方案1:用Django作为中间层,在渲染React入口页时注入数据
这种方案不需要改动React的SPA本质,只是让Django在返回React的index.html页面之前,先获取数据并嵌入到页面的全局变量里,React初始化时直接读取这个变量,不用再发请求。
步骤:
修改Django视图,获取数据并传给模板
在负责返回React入口页的Django视图里,直接查询数据库(比调用自身API更高效)或者调用API拿到数据:# views.py from django.shortcuts import render from .models import MainPageModel # 替换成你的实际模型 import json def react_index(request): # 方式1:直接查询数据库获取数据 main_page_data = list(MainPageModel.objects.all().values()) # 方式2:调用自身API(如果需要走API的权限校验等逻辑) # import requests # response = requests.get('http://127.0.0.1:8000/api/main') # main_page_data = response.json() return render(request, 'index.html', { 'main_page_data': json.dumps(main_page_data) })修改React入口模板,注入全局变量
在模板里添加script标签,把Django传来的数据转成全局变量,注意用安全的方式避免XSS:<!-- templates/index.html --> <!DOCTYPE html> <html> <head> <title>React SPA</title> </head> <body> <div id="root"></div> <!-- 用json_script过滤器安全注入数据 --> {{ main_page_data|json_script:"initial-main-data" }} <script> // 读取注入的数据到全局变量 window.__INITIAL_MAIN_DATA__ = JSON.parse(document.getElementById('initial-main-data').textContent); </script> <!-- 引入React打包后的JS文件 --> <script src="{% static 'js/main.js' %}"></script> </body> </html>修改React组件,读取全局变量替代fetch
把原本componentDidMount里的请求逻辑去掉,直接用全局变量初始化状态:class MainComponent extends React.Component { constructor(props) { super(props); // 从全局变量获取初始化数据,做个空值兜底 this.state = { MainPage: window.__INITIAL_MAIN_DATA__ || [] }; } // 移除原本的componentDidMount请求逻辑 // async componentDidMount() { ... } render() { return ( <div> {this.state.MainPage.map(item => ( <div key={item.id}>{item.content}</div> ))} </div> ); } }
方案2:改用React服务端渲染框架(比如Next.js)
如果你的项目需要更彻底的SSR特性(比如SEO优化、首屏加载速度最大化),可以把React项目迁移到Next.js,在服务端的预取函数里调用Django API。
步骤:
在Next.js页面组件中使用
getServerSideProps
这个函数会在服务端执行,获取数据后直接传给页面组件:// pages/index.js export default function Home({ MainPage }) { return ( <div> {MainPage.map(item => ( <div key={item.id}>{item.content}</div> ))} </div> ); } // 服务端执行的数据预取函数 export async function getServerSideProps() { try { // 服务端调用Django API,可直接用内部地址,无跨域问题 const res = await fetch('http://127.0.0.1:8000/api/main'); const MainPage = await res.json(); return { props: { MainPage } // 把数据作为props传给页面 }; } catch (e) { console.error('获取数据失败:', e); return { props: { MainPage: [] } // 出错时返回空数据兜底 }; } }部署时的配置
生产环境中,可以用Nginx做反向代理,把Next.js的API请求转发给Django,或者让两者部署在同一内网,服务端调用直接用内网地址即可。
注意事项
- 方案1适合现有SPA项目的快速改造,架构改动小;方案2适合需要SSR特性的新项目或SEO优化需求高的场景。
- 若用方案1,不要把敏感数据注入到全局变量,避免前端泄露。
- 服务端获取数据时,优先直接查询数据库(方案1的方式1),减少不必要的HTTP请求开销。
内容的提问来源于stack exchange,提问作者Władysław Szlianin

