Django 使用 Fetch 对 POST 请求返回 403 错误

Posted

技术标签:

【中文标题】Django 使用 Fetch 对 POST 请求返回 403 错误【英文标题】:Django returns 403 error on POST request with Fetch 【发布时间】:2017-10-07 17:37:33 【问题描述】:

我有一个使用graphene-django 实现的graphql 服务器。我可以像这样使用 jquery 对其进行查询:

function allIngredients() 
    return 'queryallProductsedgesnodename'
  
  var query = allIngredients();
  $.ajaxSetup(
    data: csrfmiddlewaretoken: ' csrf_token ' ,
  );
  $.post("/graphql", query: query, function(response) 
    console.log(response);
  )

但是,当我尝试使用 Fetch 进行此调用时,由于 CORS 问题,我得到了 403。我通过在调用之前添加 ajaxSetup... 解决了 jQuery 中的相同问题。

这是使用 fetch 的调用:

fetch('/graphql', 
        method: "POST",
        headers: 
          'Content-Type': 'application/json'
        ,
        credentials: 'include',
        body: JSON.stringify(
          csrfmiddlewaretoken: ' csrf_token ',
          query:`allProducts
            edges
              node
                id
                name
                orderPrice
                sellPrice
              
            
          `)
      
    )
    .then(function(response) 
        if (response.status >= 400) 
            throw new Error("Bad response from server");
        
        return response.json();
    )

我尝试以与在 jQuery 示例中类似的方式将 csrfmiddlewaretoken 添加到正文中,但没有运气。我尝试添加凭据:'include' as the docs say,再次没有运气。我尝试使用 credentials: 'same-origin' 并以不同的方式组合此选项,再次获得相同的结果。网络对此异常安静,我做错了什么?

【问题讨论】:

【参考方案1】:

解决方案是在 getCookie() 方法中。

  fetch("/graphql", 
        method: "POST",
        credentials: "same-origin",
        headers: 
          "X-CSRFToken": getCookie("csrftoken"),
          "Accept": "application/json",
          'Content-Type': 'application/json'
        ,
        body:JSON.stringify(query)
      )

当然,方法必须在同一页面上。取自Django Docs.

function getCookie(name) 
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') 
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) 
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) 
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            
        
    
    return cookieValue;

【讨论】:

这对我有用,非常感谢。我什至有那个 getCookie() 函数可用,我只是没有通过 fetch 标头传递它。呵呵。 我不得不重新加载,否则我的 js 代码没有更新。与 css 相同。我认为这是因为静态文件,您需要重新加载才能更新它。【参考方案2】:

如果您想使该发布请求来自不同的域(如果应用程序的前端在 React 或 Angular 中,而后端在 Django 中),请确保在设置文件中添加以下内容:

    更新 INSTALLED_APPS 以使用“coreHeaders”:

    INSTALLED_APPS = [ 'corsheaders', ]

    通过再次将以下内容添加到设置文件中,将您的前端域列入白名单:

    CORS_ORIGIN_WHITELIST = ( '本地主机:8080', )

现在允许向任何人发出此帖子请求的权限:

注意:应该在您不需要验证用户在我们的服务器上发布任何内容的情况下使用,例如,当新用户首次注册时

from rest_framework.permissions import AllowAny

class CreateUser(APIView):
    permission_classes = (AllowAny,)
    def post(self, request, format=None):
        return(Response("hi"))

【讨论】:

以上是关于Django 使用 Fetch 对 POST 请求返回 403 错误的主要内容,如果未能解决你的问题,请参考以下文章

React Express Fetch Post CORS 错误:对预检请求的响应未通过访问控制检查:它没有 HTTP ok 状态

POST请求 之 对数据进行编码处理

使用fetch-mock和isomrphic-fetch模拟post请求时,res.json()是未定义的

使用 fetch() 的 POST 请求返回 204 无内容

fetch() POST 请求,数据成为对象键 [重复]

使用fetch代替ajax请求 post传递方式