cross-domain fetch() 从页面但不是从开发控制台抛出 "Failed to fetch"

cross-domain fetch() throws "Failed to fetch" from page but not from the dev console

相关,但这在开发控制台中似乎也不起作用。

我正在直接从网页访问 restconf 服务器。静态页面由另一台服务器提供。

我正在尝试调用我创建的 RPC,但我怀疑具体细节是否重要 - 这只是一个带有 Authorization header 的 POST 请求。

我面临的问题是它可以从开发控制台运行,但不能从页面代码运行。

从开发控制台调用它工作正常:

fetch('http://172.17.0.2:8008/restconf/operations/login', {
   method: 'POST', 
   headers: {
     accept: 'application/yang-data+json', 
     authorization: 'Basic '+btoa('admin:admin')
   }
})
.then(resp => resp.json())
.then(json => console.log('session token:', json['output']['session-token']))
.then(err => console.error(err));

它输出:

session token: e6cfd60b-f96e-5d8b-b10c-16a5d71a6367

但是从页面上的代码中执行完全相同的调用(上面的逐字副本),它失败了。

请注意 http 请求实际上成功了(开发控制台显示 "status 200 OK"),但是 fetch() 仍然抛出异常(so-very-endearingly-specific TypeError: Failed to fetch)。

我可以在终端中使用 ngrep 查看请求和响应(出于某种原因开发控制台不会显示 body):

请求和响应如下:

POST /restconf/operations/login HTTP/1.1
Host: 172.17.0.2:8008
Connection: keep-alive
Content-Length: 0
Pragma: no-cache
Cache-Control: no-cache
accept: application/yang-data+json
Origin: http://localhost:5000
authorization: Basic YWRtaW46YWRtaW4=
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36
Referer: http://localhost:5000/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
HTTP/1.1 200 OK
Date: Wed, 22 Jan 2020 11:09:17 GMT
Cache-Control: private, no-cache, must-revalidate, proxy-revalidate
Content-Length: 138
Content-Type: application/yang-data+json
Pragma: no-cache
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization, X-Auth-Token
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS
Access-Control-Allow-Origin: http://localhost:5000
Content-Security-Policy: default-src 'self'; block-all-mixed-content; base-uri 'self'; frame-ancestors 'none';
Strict-Transport-Security: max-age=15552000; includeSubDomains
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block

{
  "output": {
    "session-token": "e6cfd60b-f96e-5d8b-b10c-16a5d71a6367",
    "expires": "2020-01-22T15:09:17.491906"
  }
}

(为简洁起见,省略了 OPTIONS 请求和响应。这并不令人兴奋,据我了解,如果 OPTIONS 未通过验证,则永远不会发送 POST

除了时间戳之外,这两种情况下的请求和响应都是相同的。 所以我假设浏览器在页面案例中执行了一些验证,而开发控制台不会进行这些验证。但是什么?

我在某处读到 allow-origin header 在某些情况下不允许是星号,我以前使用过。将它更改为实际的 URL 并没有改变任何东西。

非常感谢您的想法!

现在是"solved"。

原来信息丰富的 Failed to fetch,实际上是想说 Request aborted by leaving page。如果只是这么说,就可以避免很多令人头疼的事情了。

所以是的,问题是 fetch() 位于此 Q 的中心被调用以响应单击 form 中的 submit 按钮,但该按钮是错误的设置为在提交时不重新加载页面。因此,当页面重新加载时,挂起的请求被中止,抛出 Failed to fetch.

我正在使用 Svelte,我并不完全熟悉它,并且在提交时禁用页面重新加载有点不明显。至少如果你已经熟悉这样做的经典方法(即 return false)。

除了这个错误之外,我还通过在开发控制台中启用 "Preserve log" 来欺骗自己,并认为它在页面重新加载时输出的消息 "Navigated to ..." 是因为我稍后的代码链条(我是 "getting to later"...)。