【问题标题】:CORS request made despite error in console尽管控制台出错,但仍发出 CORS 请求
【发布时间】:2018-04-08 20:20:08
【问题描述】:

我正在摆弄 Google Cloud Storage。我创建了一个简单的 Python Flask 处理程序:

#!/usr/bin/env python3
import secrets

import flask
from flask_cors import CORS
from google.cloud import storage


app = flask.Flask(__name__)
CORS(app)
client = storage.Client()
bucket = client.get_bucket('<my-bucket>')


@app.route('/')
def get_upload_urls():
    blob = bucket.blob('00000' + secrets.token_hex())
    return flask.jsonify({
        'url': blob.create_resumable_upload_session(),
    })


if __name__ == '__main__':
    app.run('0.0.0.0', 9999)

这伴随着一个非常简单的网络前端:

index.html

<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1,width=device-width">
    <title>Test</title>
  </head>
  <body>
      <input id="input" type="file" />
      <button id="button">Upload</button>
      <script src="index.js"></script>
  </body>
</html>

index.js

const input = document.getElementById('input')
const button = document.getElementById('button')


button.addEventListener('click', async () => {
    const [ body ] = input.files
    const response = await fetch('http://localhost:9999')
    const { url } = await response.json()
    await fetch(url, {
        method: 'PUT',
        body,
    })
})

这个前端允许我选择一个文件,然后使用 Python 后端创建的可恢复上传会话将其上传到 Google Cloud Storage。

问题在于它确实有效。我希望 PUT 请求失败,但事实并非如此。

选择文件并按下上传按钮后,控制台会记录以下错误:

index.html:1 加载失败 https://www.googleapis.com/upload/storage/v1/b//o?uploadType=resumable&upload_id=: 请求中不存在“Access-Control-Allow-Origin”标头 资源。因此不允许使用原点“http://localhost:3333” 使用权。如果不透明的响应满足您的需求,请设置请求的 模式为“no-cors”以获取禁用 CORS 的资源。

index.js:13 Uncaught (in promise) TypeError: Failed to fetch
  async function (async)
  button.addEventListener @ index.js:5

但是,PUT 请求已成功发出,文件显示在 Google Cloud Storage 中。我可以下载它,它似乎完全没问题。

尽管控制台出现 CORS 错误,为什么 PUT 请求没有失败?

编辑

我只是在寻找解释,而不是解决方法——无论如何我都会正确配置 CORS。我只想知道为什么请求没有失败,为什么 fetch 会拒绝。

【问题讨论】:

  • 你有没有试过在获取模式中使用模式{mode: 'no-cors'}
  • CORS 防止人们从其他来源“借用”资源,远程服务器如何处理发送到它的数据显然掌握在服务器手中
  • 我能想象的唯一解释:(1)服务器发送回正确的 CORS 标头(包括 Access-Control-Allow-Origin 标头)以响应 OPTIONS 预检浏览器(自动在其own) 在尝试您的 PUT 之前执行,然后 (2) 因为预检成功,浏览器继续并从您的代码发送 PUT,然后 (3) 服务器接收 PUT 并成功处理它,但随后 (4)服务器为 PUT 发回的响应没有 Access-Control-Allow-Origin 标头,因此 (5) 您的浏览器阻止您的前端代码访问该响应
  • 您可能需要考虑更新问题以粘贴在前端代码运行时显示在浏览器 devtools 的“网络”窗格中的请求和响应的详细信息 — 包括响应,以及请求和响应的所有标头。我说 requestsresponses 复数是因为,由于您正在发出跨域 PUT 请求,您的浏览器肯定会在发送 PUT 之前发送预检 OPTIONS要求。因此,除了 PUT 的详细信息之外,您还想查看 OPTIONS 的详细信息
  • 你在这里做两个 fetches,对吧?所以大概第一个(fetch('http://localhost:9999'))失败并导致控制台条目,另一个,你的实际 PUT 请求,成功......

标签: javascript cors google-cloud-storage fetch-api


【解决方案1】:

@sideshowbarker 是对的,我也遇到了同样的问题。除了 OPTIONS 预检请求外,还需要在 PUT 响应中设置 CORS。然后fetch 将成功(即使之前上传成功)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-06
    • 2019-11-08
    • 2017-10-20
    • 2022-01-23
    • 2022-11-18
    • 2021-09-04
    • 2014-01-08
    • 1970-01-01
    相关资源
    最近更新 更多