使用所有方法发送预检请求

Preflight request is sent with all methods

我的 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,我觉得很奇怪(根据文档所说)。

我设置了一些 headers(我用 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);

我是不是漏掉了什么?

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

只需在请求中添加 Content-Type header 即可触发 CORS 预检 OPTIONS 请求——如果值是除 application/x-www-form-urlencoded、[=13= 之外的任何值],或multipart/form-data。即使对于 GET 请求也是如此(尽管你永远不应该将 Content-Type header 添加到 GET — 因为没有请求 body,所以它不服务目的)。

并且在问题中显示的 header 中,Authorization header 也会触发预检,“Language” header(这甚至不是标准的 header 名称;也许 Accept-Language 是有意的?),以及 Access-Control-Allow-Origin header(甚至不是请求 header;这是一个响应 header,永远不应在前端代码中使用。

触发预检的 header 而言: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 中的 header以上将触发预检。


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


请注意,WebKit/Safari 对 AcceptAccept-LanguageContent-Language header 中允许的值进行了额外限制。

如果这些 header 中的任何一个具有“non-standard”值,WebKit/Safari 将进行预检。

至于 WebKit/Safari 认为那些 header 的“non-standard”值,除了以下 WebKit 错误外,没有真正的记录:

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

cross-domain 问题通常发生在以下情况:应用程序托管在一个域中,网络服务托管在不同的域中,并且我们正在尝试进行 Ajax 调用以获取响应。 对我们 Web 服务的 Ajax 调用以 CORS error.The 结束,调用的 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"));
}