DRF CBV中使用Fetch发送PUT请求遇500错误的排查与解决
Django中Fetch API发送PUT/POST请求报500错误的解决方法
问题场景
通过GUI向http://localhost:8000/api/users/2发送PUT/POST请求时一切正常,但使用JavaScript Fetch API发送请求却出现500内部服务器错误,仅GET方法可正常工作。
相关JS代码如下:
function getCookie(name) { let cookieValue = null if (document.cookie && document.cookie !== ''){ let cookies = document.cookie.split(';') for(let i = 0; i< cookies.length; i++) { let cookie = cookies[i].trim() if(cookie.substring(0,name.length + 1)=== (name+'=')){ cookieValue=decodeURIComponent(cookie.substring(name.length+1)) break } } } return cookieValue } let csrfToken = getCookie('csrftoken'); let friendButton = document.querySelector('#friendButton') friendButton.addEventListener('click',()=>{ let friendID = document.querySelector('#friendID') friendID = friendID.innerHTML let friendUrl = `http://localhost:8000/api/users/${friendID}/` let userId = "{{user.id}}"; let url = `http://localhost:8000/api/users/${userId}` fetch(url) .then((resp)=>resp.json()) .then(function(data){ let list = data.friends if (!list.includes(friendUrl)) { list.push(friendUrl); } const updatedUserData = { friends: list }; fetch(url,{ method:"PUT", headers:{ 'Content-Type': 'application/json', 'X-CSRFToken': csrfToken, }, body: JSON.stringify(updatedUserData), }) .then((resp)=>{ if (resp.status === 200) { console.log("Friend added successfully!"); } else { console.error("Unexpected status code: " + resp.status); } }) .catch((err)=>{ console.error("Error:", err); }); }) .catch((err)=>{ console.error("Error:", err); }); })
错误原因分析
查看Django日志,明确错误根源:
Internal Server Error: /api/users/2 Traceback (most recent call last): ... RuntimeError: You called this URL via PUT, but the URL doesn't end in a slash and you have APPEND_SLASH set. Django can't redirect to the slash URL while maintaining PUT data. Change your form to point to localhost:8000/api/users/2/ (note the trailing slash), or set APPEND_SLASH=False in your Django settings.
Django默认开启APPEND_SLASH配置,当请求URL未以斜杠结尾时,会自动重定向到带斜杠的URL。但PUT请求的请求体无法在重定向过程中保留,因此触发500内部服务器错误。
排查与解决过程
- 尝试关闭APPEND_SLASH:将Django配置中
APPEND_SLASH设为False,但出现404错误,说明后端路由定义的是带尾斜杠的URL。 - 添加URL尾斜杠:给请求URL加上尾斜杠后,出现400错误,推测是后端视图对PUT请求的处理逻辑存在问题(比如要求全量更新但请求数据不完整)。
- 改用PATCH方法:将请求方法从PUT改为PATCH后,问题解决。PATCH方法用于部分更新资源,更符合当前仅修改
friends字段的场景,同时避免了PUT请求带来的重定向或全量更新校验问题。
修正后的关键代码
将Fetch请求的方法从PUT改为PATCH即可:
fetch(url,{ method:"PATCH", // 修改为PATCH方法 headers:{ 'Content-Type': 'application/json', 'X-CSRFToken': csrfToken, }, body: JSON.stringify(updatedUserData), })
同时需要确保后端视图支持PATCH方法:
- 如果使用Django REST Framework的类视图,需在视图类中添加
PATCH到允许的方法列表,比如:class UserView(generics.RetrieveUpdateAPIView): queryset = User.objects.all() serializer_class = UserSerializer http_method_names = ['get', 'put', 'patch'] # 包含PATCH - 如果使用函数视图,需用装饰器指定允许的方法:
from rest_framework.decorators import api_view @api_view(['GET', 'PUT', 'PATCH']) def user_detail(request, pk): # 视图逻辑 pass
内容的提问来源于stack exchange,提问作者Patryk Opiela
相关产品推荐
相关产品推荐

