跨域 fetch() 从页面而不是从开发控制台抛出“无法获取”

Posted

技术标签:

【中文标题】跨域 fetch() 从页面而不是从开发控制台抛出“无法获取”【英文标题】:cross-domain fetch() throws "Failed to fetch" from page but not from the dev console 【发布时间】:2020-05-08 14:09:30 【问题描述】:

与Getting "TypeError: failed to fetch" when the request hasn't actually failed 相关,但这似乎在开发控制台中也不起作用。

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

我正在尝试调用我创建的 RPC,但我怀疑具体细节是否重要——它只是一个带有 Authorization 标头的 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 请求实际上成功了(开发控制台显示“状态 200 OK”),但 fetch() 仍然抛出异常(非常可爱的特定 TypeError: Failed to fetch)。

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

以下是请求和响应:

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 标头不允许使用星号,我之前使用过。将其更改为实际 URL 并没有改变任何内容。

非常感谢您的想法!

【问题讨论】:

【参考方案1】:

现在已经“解决”了。

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

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

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

除了这个错误之外,我还通过在开发控制台中启用“保留日志”来欺骗自己,并认为它在页面重新加载时输出的消息“导航到...”是因为我稍后在链(我正在“稍后”......)。

【讨论】:

以上是关于跨域 fetch() 从页面而不是从开发控制台抛出“无法获取”的主要内容,如果未能解决你的问题,请参考以下文章

ajax跨域问题-web开发必会

如何从页面模板上调用的函数而不是从ins获取当前页面永久链接url

响应式 Iframe 高度跨域,无需控制源页面

fetch(),如何发出非缓存请求?

当我从 Azure 函数而不是从控制台应用程序运行 LINQ 查询时,它会失败

原fetch跨域请求附带cookie(credentials)