问题
My FE application is using API from different domain. I know that it should trigger CORS, but as I understood it shouldn't create preflight for every request.
According to docs, I shouldn't have preflight request for GET
method.
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)
However, every request that I'm sending, has preflight (OPTIONS) request, no matter if it's GET or POST, and I find it strange (according to what docs said).
I set some headers (and I'm sending it with withCredentials: true
), but I don't see that it should be the issue:
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);
Am I missing something?
回答1:
See https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Simple_requests
Even for GET requests, the only allowed values for the Content-Type
header in a simple request are application/x-www-form-urlencoded
, multipart/form-data
, and text/plain
. Any other Content-Type value will trigger browsers to do a preflight.
That follows from the fact the Fetch spec (which defines CORS behavior) specifies what it calls a CORS-safelisted request-header, which it defines as one of:
Accept
Accept-Language
Content-Language
Content-Type
and whose value, once parsed, has a MIME type (ignoring parameters) that isapplication/x-www-form-urlencoded
,multipart/form-data
, ortext/plain
Any request—including any GET request—that contains a header that’s not a CORS-safelisted request-header triggers a preflight.
To help make all this more clear, I updated the MDN documentation about CORS “simple requests” and the MDN documentation about CORS preflighted requests (it’s slightly more complicated than what’s described above, actually—but what’s above suffices for the context of this question).
Note that WebKit/Safari places additional restrictions on the values allowed in the Accept
, Accept-Language
, and Content-Language
headers.
If any of those headers have ”non-standard” values, WebKit/Safari will do a preflight.
As far as what WebKit/Safari considers “non-standard” values for those headers, that’s not really documented except in the following WebKit bugs:
- Require preflight for non-standard CORS-safelisted request headers Accept, Accept-Language, and Content-Language
- Allow commas in Accept, Accept-Language, and Content-Language request headers for simple CORS
- Switch to a blacklist model for restricted Accept headers in simple CORS requests
No other browsers implement those extra restrictions, because they’re not part of the spec. They were unilaterally added to WebKit without any discussion with the spec editor or other browsers.
回答2:
The cross-domain issue typically occurs when the application is hosted on one domain, the web service is hosted on a different domain and we are trying to make an Ajax call to get the response. An Ajax call to our web services ended with a CORS error.The HTTP method that was invoked was OPTIONS and not GET or POST.
Resolving this issue was one aspect but we still needed to retain the security authentication. Otherwise, we would end up exposing an unauthenticated web service which is a threat.
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"));
}
来源:https://stackoverflow.com/questions/41679725/preflight-request-is-sent-with-all-methods