使用Fetch更新数据库时出现CSRF Token缺失错误
解决Fetch POST请求403 Forbidden(CSRF Token缺失)问题
我尝试用Fetch API更新数据库条目时,控制台出现403 Forbidden错误,日志提示CSRF Token缺失。我的HTML未使用表单,仅通过JS将元素追加到div中,相关代码如下:
document.addEventListener("DOMContentLoaded", function(){ const button = document.querySelectorAll("#edit_profile") button.forEach(function(button){ button.onclick = function(){ const memberID = button.dataset.id; const usernameID = button.dataset.username; const username = document.getElementById(`username_${memberID}`); let edit_username = document.createElement("textarea"); edit_username.setAttribute("rows", "1"); edit_username.innerHTML = username.innerHTML edit_username.id = `edit_username_${memberID}`; edit_username.className = `form-control username ${usernameID}`; const saveButton = document.createElement("button"); saveButton.innerHTML = "Save"; saveButton.id = `saveButton_${memberID}`; saveButton.className = "btn btn-success col-3"; saveButton.style.margin = "10px"; document.getElementById(`edit_${memberID}`).append(edit_username); document.getElementById(`edit_${memberID}`).append(saveButton); saveButton.addEventListener("click", function(){ edit_username = document.getElementById(`edit_username_${memberID}`); fetch(`/edit_profile/${memberID}`,{ method: "POST", body: JSON.stringify({ username: edit_username.value, }) }) .then(response => response.json()) .then(result => { console.log(result); if(result[`error`]){ reset(memberID) } else { username.innerHTML = result.username; reset(memberID) } }) .catch(error => { console.error(error); }) }) } }); });
问题原因
后端启用了CSRF(跨站请求伪造)防护机制,所有POST请求必须携带有效的CSRF Token才能通过验证,你的Fetch请求没包含这个Token,所以被拦截返回403。
解决方案
方法1:从页面meta标签获取Token并添加到请求头
首先确认HTML页面中存在后端生成的CSRF Token meta标签(大多数后端框架会自动注入,比如Django、Flask-WTF):
<meta name="csrf-token" content="后端生成的CSRF Token值">
然后修改Fetch请求代码,添加请求头:
saveButton.addEventListener("click", function(){ edit_username = document.getElementById(`edit_username_${memberID}`); // 获取meta标签中的CSRF Token const csrfToken = document.querySelector('meta[name="csrf-token"]').content; fetch(`/edit_profile/${memberID}`,{ method: "POST", headers: { 'Content-Type': 'application/json', // 必须指定JSON格式 'X-CSRFToken': csrfToken // 添加CSRF Token请求头 }, body: JSON.stringify({ username: edit_username.value, }) }) .then(response => response.json()) .then(result => { console.log(result); if(result.error){ reset(memberID) } else { username.innerHTML = result.username; reset(memberID) } }) .catch(error => { console.error(error); }) })
方法2:从Cookie读取CSRF Token(部分框架支持)
如果后端将CSRF Token存储在Cookie中(比如Django默认存在csrftoken Cookie),可以通过JS读取Cookie并添加到请求头:
// 封装读取Cookie的函数 function getCookie(name) { let cookieValue = null; if (document.cookie && document.cookie !== '') { const cookies = document.cookie.split(';'); for (let i = 0; i < cookies.length; i++) { const cookie = cookies[i].trim(); if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } // 修改Fetch请求部分 saveButton.addEventListener("click", function(){ edit_username = document.getElementById(`edit_username_${memberID}`); const csrfToken = getCookie('csrftoken'); // 替换为对应Cookie名称 fetch(`/edit_profile/${memberID}`,{ method: "POST", headers: { 'Content-Type': 'application/json', 'X-CSRFToken': csrfToken }, body: JSON.stringify({ username: edit_username.value, }) }) // 后续then/catch逻辑不变 })
注意事项
- 发送JSON数据时,必须设置
Content-Type: application/json请求头,否则后端无法正确解析请求体 - 不同后端框架的CSRF请求头名称可能不同,比如部分框架使用
X-CSRF-TOKEN,请根据后端配置调整
内容的提问来源于stack exchange,提问作者user17470872
相关产品推荐
相关产品推荐

