【问题标题】:Preflight request is sent with all methods使用所有方法发送预检请求
【发布时间】:2017-05-31 11:43:25
【问题描述】:

我的 FE 应用程序正在使用来自不同域的 API。我知道它应该触发 CORS,但据我了解,它不应该为每个请求创建预检。

根据docs,我不应该有GET 方法的预检请求。

 Cross-site requests are preflighted like this since they may have implications to 
 user data. In particular, a request is preflighted if:

    - It uses methods other than GET, HEAD or POST. 
Also, if POST is used to send request data with a Content-Type 
other than application/x-www-form-urlencoded, multipart/form-data, 
or text/plain, e.g. if the POST request sends an XML payload to the
server using application/xml or text/xml, then the request is preflighted.
    - It sets custom headers in the request 
(e.g. the request uses a header such as X-PINGOTHER)

但是,我发送的每个请求都有预检 (OPTIONS) 请求,无论是 GET 还是 POST,我觉得这很奇怪(根据文档所说)。

我设置了一些标题(我用withCredentials: true 发送它),但我不认为这应该是问题:

  headers.append('Access-Control-Allow-Origin', FRONTEND_URL);
  headers.append('Accept', 'application/json');
  headers.append('Content-Type', 'application/json');
  headers.append('Authorization', this._generateApiKey());
  headers.append('Language', this._languageISOCode);

我错过了什么吗?

【问题讨论】:

  • WithCredentials 是您的自定义标头,这意味着它会针对 GET/POST 请求进行预检

标签: javascript angular cors preflight


【解决方案1】:

https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Simple_requests

只需向请求添加 Content-Type 标头即可触发 CORS 预检 OPTIONS 请求 — 如果值是除 application/x-www-form-urlencodedtext/plainmultipart/form-data 之外的任何值。即使对于 GET 请求也是如此(尽管您永远不应该将 Content-Type 标头添加到 GET ——因为没有请求正文,所以它没有任何用途)。

在问题中显示的标头中,Authorization 标头也将触发预检,“Language”标头(甚至不是标准标头名称;也许 Accept-Language 是有意的? ) 和 Access-Control-Allow-Origin 标头(甚至不是请求标头;它是一个响应标头,不应在前端代码中使用)。

触发预检的标头而言:Fetch 规范(定义 CORS 行为)指定它所谓的 CORS-safelisted request-header,并定义为以下之一:

  • Accept
  • Accept-Language
  • Content-Language
  • Content-Type 的值在解析后具有 MIME 类型(忽略参数)为 application/x-www-form-urlencodedmultipart/form-datatext/plain

任何请求 - 包括任何 GET 请求 - 包含的标头不在上面列出的 CORS-safelisted request-headers 中,都将触发预检。


为了更清楚地说明这一切,我更新了 the MDN docs about CORS “simple requests”the MDN docs about CORS preflighted requests(实际上它比上面描述的稍微复杂一些,但上面的内容足以满足这个问题的上下文)。


请注意,WebKit/Safari 对 AcceptAccept-LanguageContent-Language 标头中允许的值设置了额外的限制。

如果这些标头中的任何一个具有“非标准”值,WebKit/Safari 将进行预检。

就 WebKit/Safari 认为这些标头的“非标准”值而言,除了以下 WebKit 错误外,并没有真正记录在案:

没有其他浏览器施加这些额外的限制,因为它们不是规范的一部分。它们被单方面添加到 WebKit 中,没有与规范编辑器或其他浏览器讨论。

【讨论】:

  • 这不是 CORS 安全列表中的请求标头 - 您的意思是它不在您显示的 4 个标头列表中吗?
  • 是的,任何不在上述 4 个标头列表中的标头。
【解决方案2】:

跨域问题通常发生在应用程序托管在一个域上,Web 服务托管在另一个域上,并且我们试图进行 Ajax 调用以获取响应时。 对我们的 Web 服务的 Ajax 调用以 CORS 错误结束。调用的 HTTP 方法是 OPTIONS,而不是 GET 或 POST。

解决这个问题是一方面,但我们仍然需要保留安全身份验证。否则,我们最终会暴露未经身份验证的 Web 服务,这是一种威胁。

if (request.getMethod().equals("OPTIONS") && request.getHeader(ORIGIN).equals(FRONTEND_URL))
{
response.setHeader("Access-Control-Allow-Origin", FRONTEND_URL);
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, HEAD");
response.setHeader("Access-Control-Allow-Headers",request.getHeader("Access-Control-Request-Headers"));
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-24
    • 1970-01-01
    • 2022-11-28
    相关资源
    最近更新 更多