Django部署至Apache服务器后Fetch提交表单返回403 Forbidden错误求助
兄弟,看你卡这个问题好几天了,太懂这种本地跑顺风顺水,一部署就掉坑的滋味!结合你给的代码和描述,我给你梳理几个大概率的问题点,你挨个排查试试:
1. Fetch请求的Content-Type设置冲突(大概率是403的元凶)
你在main.js里手动设置了headers: { 'Content-Type': 'application/x-www-form-urlencoded' },但同时用了new FormData(form)作为请求体——这俩是完全不兼容的!
FormData默认对应的Content-Type是multipart/form-data; boundary=xxx,浏览器会自动生成这个头。你强行改成x-www-form-urlencoded后,服务器没法正确解析FormData里的内容,包括表单里的CSRF令牌,Django的CSRF验证自然就失败了,直接返回403。
解决办法:把fetch里的手动Content-Type配置删掉,让浏览器自动处理,同时手动带上CSRF令牌做双重保险。修改后的代码如下:
const form = document.getElementById('form'); form.addEventListener("submit", submitHandler); // 新增获取CSRF 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; } function submitHandler(e) { e.preventDefault(); fetch("{% url 'messages-api' %}", { credentials: "include", method: 'POST', headers: { 'X-CSRFToken': getCookie('csrftoken') }, body: new FormData(form) }) .then(response => response.json()) .then(data => { alert("Got your message") }) .catch(err => console.error('请求出错:', err)); // 加个catch方便排查前端报错 }
2. 去掉Content-Type后出现500?大概率是邮件发送的锅
你说去掉那个头后,表单能存进数据库,但过两分钟报500,这说明表单提交本身是成功的,问题出在服务器端发送邮件的环节。本地能发邮件,生产环境不行,常见原因有:
- Django的邮件配置(
settings.py里的EMAIL_HOST、EMAIL_PORT、EMAIL_HOST_USER等)在生产环境是不是没配置对?比如SMTP服务器需要SSL/TLS,本地可能忽略了,但生产环境必须开启EMAIL_USE_SSL或EMAIL_USE_TLS。 - Apache的运行用户(一般是
www-data)有没有权限访问邮件相关资源?或者服务器防火墙是不是挡住了SMTP端口(比如25、465、587)? - 邮件发送超时!本地测试邮件发送很快,但生产环境SMTP连接慢,导致请求超时触发500错误。
解决办法:立刻去看Django的日志或者Apache的错误日志(一般在/var/log/apache2/目录下),找到500错误的具体堆栈信息,日志会明确告诉你是SMTP连接失败、认证错误还是超时,一目了然。
3. 再确认下权限配置(虽然你改了,但再检查一遍)
你给了templates文件夹权限,但还要确认:
- Apache的运行用户(
www-data)对/home/admin/pinpoint整个目录有没有读权限?尤其是venv虚拟环境和project目录。 media文件夹有没有写权限?不过你说表单能存数据库,这个可能不是问题,但以防万一。- 你的
ssl.conf里的路径是不是都正确?比如WSGIScriptAlias / /home/admin/pinpoint/project/wsgi.py这个路径有没有写错?
按这个顺序排查,先搞定Content-Type的问题解决403,再通过日志定位500的邮件问题,应该就能顺利解决了!
备注:内容来源于stack exchange,提问作者user13506452

