使用fetch() API请求Django视图后,重定向丢失messages消息如何解决?
问题原因
fetch API默认会自动跟随重定向,导致在你调用location.replace()之前,浏览器已经悄悄向重定向目标URL发送了GET请求。Django的messages框架会在这次请求中读取并清除session里的消息,所以当你手动跳转时,session中已经没有消息可显示了。
解决方案
方案一:阻止fetch自动跟随重定向(推荐)
修改JavaScript中的请求配置,添加redirect: "manual"来禁止自动跟随,然后手动获取重定向URL再跳转:
修改后的JavaScript代码
var csrftoken = document.querySelector('[name=csrfmiddlewaretoken]').value; const headers = new Headers(); headers.append("X-CSRFToken", csrftoken); const form = new FormData(); form.append("pproject", "{{ project.id }}"); const ops = { method: "POST", headers: headers, body: form, credentials: "same-origin", redirect: "manual" // 新增:阻止自动跟随重定向 }; const req = new Request("{% url 'project_add' %}"); fetch(req, ops) .then((response) => { // 处理3xx重定向状态码 if (response.status >= 300 && response.status < 400) { const redirectUrl = response.headers.get('Location'); window.location.replace(redirectUrl); } else if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } else { return response.json(); } })
这样fetch不会提前访问重定向目标,只有当你手动调用location.replace()时才会发起第一次请求,messages会被正确读取并显示。
方案二:视图返回JSON携带消息和重定向URL
如果需要更灵活的前端控制,可以修改Django视图,返回包含消息和重定向地址的JSON,前端存储消息后再跳转:
修改后的Django视图代码
from django.http import JsonResponse from django.urls import reverse import messages def add(request): if request.method != 'POST': return HttpResponse("not post") pproject = request.POST['pproject'] print("pproject:", pproject) message_content = "Test." # 返回JSON数据 return JsonResponse({ 'redirect_url': reverse('project_detail'), 'message': message_content, 'message_level': 'INFO' })
修改后的前端JavaScript代码
// (前面的请求配置不变) fetch(req, ops) .then((response) => { if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } else { return response.json(); } }) .then((data) => { // 将消息存入sessionStorage sessionStorage.setItem('django_message', JSON.stringify({ text: data.message, level: data.message_level })); // 跳转到目标页面 window.location.replace(data.redirect_url); })
目标页面添加消息显示逻辑
在目标页面的模板中添加JavaScript,读取存储的消息并显示:
<script> document.addEventListener('DOMContentLoaded', () => { const storedMsg = sessionStorage.getItem('django_message'); if (storedMsg) { const { text, level } = JSON.parse(storedMsg); // 创建符合Django消息样式的元素 const msgElement = document.createElement('div'); msgElement.className = `alert alert-${level.toLowerCase()}`; msgElement.textContent = text; // 插入到页面的消息容器(假设容器id为messages) const msgContainer = document.getElementById('messages'); if (msgContainer) msgContainer.appendChild(msgElement); // 清除存储的消息 sessionStorage.removeItem('django_message'); } }); </script>
内容的提问来源于stack exchange,提问作者dequid
相关产品推荐
相关产品推荐

