Django单页应用首页Jobs加载失败,重试后恢复问题求助
问题分析与解决方案
核心问题定位
报错Unexpected token '<', "<!doctype "... is not valid JSON说明前端请求Jobs数据接口时,服务器返回的是HTML页面(而非预期的JSON数据)。结合"多次点击/刷新后恢复、其他页面正常"的现象,大概率是后端路由匹配优先级冲突或Nginx请求转发的偶发异常,导致API请求被错误路由到了单页应用的入口HTML。
排查与修复步骤
1. 调整Django后端路由优先级
确保API接口路由在单页应用入口路由之前定义,避免Django误将API请求匹配到首页HTML。
示例urls.py修改:
# urls.py from django.urls import path, re_path from django.views.generic import TemplateView # 先定义Jobs的API接口路由 path('api/jobs/', views.get_jobs_data, name='api_jobs'), # 再定义单页应用的兜底路由(匹配所有未被前面路由命中的路径) re_path(r'^.*$', TemplateView.as_view(template_name='index.html')),
注意:如果你的API路由是
/jobs/而非带/api/前缀,极可能和前端路由/jobs/冲突,导致Django优先返回HTML。建议给所有API接口统一加上/api/前缀做区分。
2. 修正Nginx的转发与缓存逻辑
Nginx的缓存或路由匹配规则可能偶发将API请求转发到静态HTML文件,而非Django后端。
推荐Nginx配置调整:
server { listen 443 ssl; server_name pythonyard.com; # 静态文件直接返回,不转发到Django location /static/ { alias /path/to/your/project/static/; expires 30d; } # API请求单独处理,优先转发到Django后端 location /api/ { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # 禁用API请求的缓存,避免返回旧的HTML内容 proxy_no_cache 1; proxy_cache_bypass 1; } # 单页应用其他请求返回入口HTML location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # 仅当请求路径不存在时返回入口HTML,避免API请求被误匹配 try_files $uri $uri/ /index.html; } }
3. 优化前端请求逻辑
前端调用locationHandler加载Jobs内容时,增加请求校验和重试逻辑,处理偶发的转发异常:
示例前端代码修改:
async function loadJobsData() { try { const response = await fetch('/api/jobs/'); // 先校验响应状态,再解析JSON if (!response.ok) { throw new Error(`请求失败:${response.status}`); } // 明确要求JSON格式,避免返回HTML if (!response.headers.get('content-type')?.includes('application/json')) { throw new Error('返回内容不是JSON'); } const data = await response.json(); locationHandler(data); // 填充Jobs内容 } catch (error) { console.error('Jobs数据加载失败,重试中:', error); // 短延迟后重试一次,解决偶发的转发问题 setTimeout(loadJobsData, 500); } } // 首页加载时自动触发请求 window.addEventListener('load', () => { const currentPath = window.location.pathname; if (currentPath === '/' || currentPath === '/jobs/') { loadJobsData(); } });
4. 校验Django CSRF配置(若API用POST)
如果Jobs接口是POST请求,确保前端正确携带CSRF token,避免因验证失败返回HTML错误页:
// 从Cookie中获取CSRF token function getCSRFToken() { let token = null; const cookies = document.cookie.split(';'); for (const cookie of cookies) { const [key, value] = cookie.trim().split('='); if (key === 'csrftoken') { token = decodeURIComponent(value); break; } } return token; } // 请求时携带CSRF token和JSON接受头 const response = await fetch('/api/jobs/', { method: 'POST', headers: { 'X-CSRFToken': getCSRFToken(), 'Accept': 'application/json', 'Content-Type': 'application/json' }, body: JSON.stringify({/* 请求参数 */}) });
验证方法
- 重启Nginx和Django服务:
sudo systemctl restart nginx、sudo systemctl restart gunicorn(若使用gunicorn部署) - 清空浏览器缓存,打开控制台"网络"面板,监控Jobs页面加载时的API请求,确认返回内容为JSON而非HTML
- 多次刷新首页,验证是否还出现加载失败的情况
内容的提问来源于stack exchange,提问作者Xceptions
相关产品推荐
相关产品推荐

