跨域 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() 从页面而不是从开发控制台抛出“无法获取”的主要内容,如果未能解决你的问题,请参考以下文章
如何从页面模板上调用的函数而不是从ins获取当前页面永久链接url