Fetch API 默认跨域行为

2022-01-20 00:00:00 cors fetch javascript fetch-api

Fetch Specifications 说默认的 Fetch 模式是 'no-cors' -

The Fetch Specifications say that the default Fetch mode is 'no-cors' -

请求具有关联的模式,即same-origin"、cors"、no-cors"、navigate"或websocket".除非另有说明,否则它是no-cors".

A request has an associated mode, which is "same-origin", "cors", "no-cors", "navigate", or "websocket". Unless stated otherwise, it is "no-cors".

但是,我似乎注意到 mode: 'no-cors' 和未指定模式之间的这种行为差异.正如此 JSFiddle 示例 中所展示的,将模式显式定义为 'no-cors' 会使响应无法访问Javascript,虽然没有指定模式,但 Response 对象可用于调用方法.

But, I seem to be noticing this behavioral difference between mode: 'no-cors' and an unspecified mode. As demonstrated in this JSFiddle sample, explicitly defining mode as 'no-cors' makes the response inaccessible to the Javascript, while not specifying a mode makes the Response object available to the calling method.

显式指定获取模式的工作方式与内部使用相同模式的默认行为不同吗?我在这里错过了什么?

Does explicitly specifying the fetch mode work differently from the default behavior that internally uses the same mode? What am I missing here?

推荐答案

对于跨域请求,Fetch 算法设置 response tainting" 用于对 cors 的请求,并要求使用 CORS 协议.

For cross-origin requests, the Fetch algorithm sets the "response tainting" for the request to cors and requires the fetch to be performed using the CORS protocol.

具体而言,请参见 主要获取"算法的第 12 步的以下子步骤:

↪ request 的当前 url 的来源与 request 的来源相同原点和 CORS 标志未设置
↪ 请求当前url的scheme是data"
↪ 请求的模式是navigate"或websocket"
1. 将请求的响应污染设置为basic".
2. 返回使用 request 执行方案获取的结果.

↪ request 的模式是no-cors"
1. 将 request 的响应污染设置为opaque".
2. 返回使用 request 执行方案获取的结果.

↪ 否则
1. 将请求的响应污染设置为cors".
2. 使用设置了CORS标志的请求返回执行HTTP fetch的结果.

↪ request’s current url’s origin is same origin with request’s origin and CORS flag is unset
↪ request’s current url’s scheme is "data"
↪ request’s mode is "navigate" or "websocket"
1. Set request’s response tainting to "basic".
2. Return the result of performing a scheme fetch using request.

↪ request’s mode is "no-cors"
1. Set request’s response tainting to "opaque".
2. Return the result of performing a scheme fetch using request.

↪ Otherwise
1. Set request’s response tainting to "cors".
2. Return the result of performing an HTTP fetch using request with CORS flag set.

这相当于,如果请求 URL 与您的代码的来源不同,并且方案不是 data 并且模式不是 navigatewebsocket 或未明确设置为 no-cors,则达到 Otherwise 条件,并使用CORS 协议.

What it amounts to is, if the request URL isn’t same-origin with your code’s origin, and the scheme isn’t data and the mode isn’t navigate or websocket or isn’t explicitly set to no-cors, then that Otherwise condition gets reached, and the request gets made using the CORS protocol.

这种解释稍微简化了一些事情,因为在请求具有触发浏览器进行预检的特征的情况下,在否则子步骤的上方会有一个子步骤,但会再次到达在这种情况下,响应污染"被设置为 cors.

That explanation simplifies things a bit because in the case where the request has characteristics that trigger the browser to do a preflight, there’s a substep just above that Otherwise substep that gets reached instead—but again in that case, the "response tainting" gets set to cors.

但是,我似乎注意到 mode: 'no-cors' 和未指定模式之间的这种行为差异.

But, I seem to be noticing this behavioral difference between mode: 'no-cors' and an unspecified mode.

不同之处在于,当您为请求显式设置 mode: 'no-cors' 时,在这种情况下 ↪ 请求的模式为no-cors"" 到达子步骤而不是 否则 子步骤.

The difference is because when you explicitly set mode: 'no-cors' for the request, in that case the "↪ request’s mode is "no-cors"" substep gets reached instead of the Otherwise substep.

(虽然我认为也许可以改进规范,以更清楚地表明此时的模式实际上并不只是默认为 no-cors ——否则你可能会得出这样的结论除非另有说明,否则它是问题中引用的规范中的no-cors"" 声明.)

(Though I think maybe the spec could be refined to make it more clear that the mode at that point doesn’t actually just default to no-cors—which is what you might otherwise conclude based on the "Unless stated otherwise, it is "no-cors"" statement from the spec cited in the question.)

正如这个 JSFiddle 示例中所展示的,将模式显式定义为no-cors"会使 Javascript 无法访问响应,

As demonstrated in this JSFiddle sample, explicitly defining mode as 'no-cors' makes the response inaccessible to the Javascript,

是的——那是因为它会导致 ↪ 请求的模式是no-cors"" 子步骤在Main fetch"算法中到达,而不是 Otherwise子步骤.

Right—that’s because it causes the "↪ request’s mode is "no-cors"" substep in the "Main fetch" algorithm to get reached instead of the Otherwise substep.

如果不指定模式,则 Response 对象可用于调用方法.

while not specifying a mode makes the Response object available to the calling method.

因为 Otherwise 子步骤确实会到达,所以会执行启用 CORS 的提取.

Because the Otherwise substep does then get reached, so a CORS-enabled fetch gets performed.

显式指定获取模式的工作方式与内部使用相同模式的默认行为不同吗?

Does explicitly specifying the fetch mode work differently from the default behavior that internally uses the same mode?

是的,对于跨域请求,显式设置 mode: 'no-cors' 会强制在不使用 CORS 的情况下发出请求,而未指定会导致使用 CORS 发出请求.

Yes, for a cross-origin request, explicitly setting mode: 'no-cors' forces the request to be made without using CORS, while leaving it unspecified causes it to be made using CORS.

但如上所述,我认为也许应该完善规范以使其更加清晰.

But as mentioned above, I think maybe the spec should get refined to be a bit more clear on this.

我认为 除非另有说明,否则关于模式的no-cors"" 声明绝对不是为了指定使用没有明确指定模式的 fetch(...) 方法最终会将其模式锁定为 no-cors.

I think that "Unless stated otherwise, it is "no-cors"" statement about the mode definitely isn’t meant to specify that requests that get made using the fetch(…) method without an explicit mode specified end up having their mode locked into no-cors.

相关文章