You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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内部服务器错误。

排查与解决过程

  1. 尝试关闭APPEND_SLASH:将Django配置中APPEND_SLASH设为False,但出现404错误,说明后端路由定义的是带尾斜杠的URL。
  2. 添加URL尾斜杠:给请求URL加上尾斜杠后,出现400错误,推测是后端视图对PUT请求的处理逻辑存在问题(比如要求全量更新但请求数据不完整)。
  3. 改用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 19:50:32