浏览器向 django 发出 CORS 请求的 OPTIONS 请求,但没有 POST

Posted

技术标签:

【中文标题】浏览器向 django 发出 CORS 请求的 OPTIONS 请求,但没有 POST【英文标题】:Browser makes OPTIONS request to django for CORS request, but no POST 【发布时间】:2019-08-29 21:03:41 【问题描述】:

我正在尝试通过 post 将来自 react 应用程序的表单提交到不同来源的 django 服务器。

浏览器发送一个 OPTIONS 请求,服务器上的 cors 中间件以 200 响应该请求,并提供以下信息:

HTTP/1.1 200 OK
Date: Mon, 08 Apr 2019 16:34:38 GMT
Server: WSGIServer/0.2 CPython/3.7.2
Content-Type: text/html; charset=utf-8
Content-Length: 0
Vary: Origin
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: accept, accept-encoding, authorization, content-type, dnt, origin, user-agent, x-csrftoken, x-requested-with
Access-Control-Allow-Methods: DELETE, GET, OPTIONS, PATCH, POST, PUT
Access-Control-Max-Age: 86400
Connection: keep-alive

但浏览器随后从未发出 POST 请求。它在控制台中没有显示任何错误...

【问题讨论】:

所以这是一个有效的预检响应,并且预检没有失败(如果失败,浏览器会记录一个特定的错误)——鉴于此,没有任何东西阻止浏览器进行来自您的代码的 POST 请求。所以我不知道为什么浏览器不这样做。您是否在其他浏览器中尝试过,您是否在其他浏览器中看到相同的行为?您是否尝试过更改(暂时,仅用于测试)请求的特征(例如,请求标头),使其不会触发预检,并且在这种情况下,POST 是否按预期发生? 你是如何断定浏览器没有发出 POST 请求的?如果您在 devtools 中打开 Network 窗格并重新加载,POST 请求是否不会在 OPTIONS 请求之后显示在那里? @sideshowbarker django 开发服务器列出了它收到的所有请求。它接收 OPTIONS,但没有后续的 POST。如果我将模式切换为“no-cors”,服务器确实会收到一个 POST 请求。 好的,我知道这就是您从服务器端看到的。但是您在浏览器 devtools 的“网络”选项卡中的客户端看到了什么?例如,可以想象浏览器实际上正在发出 POST 请求,但随后又被取消了。而且就像我说的那样,您是否在任何其他浏览器中尝试过,您是否看到相同的行为? @sideshowbarker 抱歉耽搁了。现在有一个错误:Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.。根据devtools,没有发出POST请求......不同的浏览器做同样的事情 【参考方案1】:

尝试安装django-cors-headers (https://pypi.org/project/django-cors-headers/) 应用程序并将CORS_ORIGIN_ALLOW_ALL = True 添加到您的django 设置文件中。这是解决问题的最简单方法,此应用程序为您提供了许多 CORS 自定义选项。

或者您可以编写自定义中间件并为每个响应添加 CORS 标头。

否则,您可以将 CORS 标头配置添加到您的网络服务器(nginx、apache 等)。

【讨论】:

我已经这样做了,这就是对初始 OPTIONS 请求的响应 您是否为 CORS 使用任何浏览器扩展程序?如果是这样,请禁用它们。 不,不是那样的 尽管如此,我认为这个问题是有问题的。您可以使用 Postman 或 CURL 发送请求并查看响应标头。【参考方案2】:

去检查请求响应的元素,并检查那里是否有任何“headers are not allowed”消息。

如果是这样,请将该标头添加到 django settings.py 中的 CORS_ALLOW_HEADER = ['that-header']

就我而言,缓存控制标头是不允许的。所以我添加了它,它起作用了。

【讨论】:

【参考方案3】:

事实证明,您必须将 Cache-Control 添加到 CORS_ALLOW_HEADERS 才能使其正常工作。一些浏览器不处理将其设置为“*”。这是我的设置:

CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_METHODS = [
    "DELETE",
    "GET",
    "OPTIONS",
    "PATCH",
    "POST",
    "PUT",
]
CORS_ALLOW_HEADERS = [
    "accept",
    "accept-encoding",
    "authorization",
    "content-type",
    "dnt",
    "origin",
    "user-agent",
    "x-csrftoken",
    "x-requested-with",
    "cache-control",
    "pragma",
]

【讨论】:

以上是关于浏览器向 django 发出 CORS 请求的 OPTIONS 请求,但没有 POST的主要内容,如果未能解决你的问题,请参考以下文章

如何在 django 的预检 CORS POST 请求中处理 CSRF?

尝试在 https://api.thetvdb.com/ 向 TVDB REST API 发出 JSON POST 请求,但出现 CORS 错误

使用 Django 和 Angular 的 CORS 预检请求

Cors

来自 Django 服务器的 reactjs 请求时出错(403 错误/CORS)

在 Django 中使用 Axios 和 CORS 获取 POST 请求的错误请求并做出反应